未验证 提交 7681692b 编写于 作者: W Will Smith 提交者: GitHub

[JIT] CodeGen verification testing (#75102)

* Add test

* Add CHECKs

* Build scripts and test settings

* COMPlus -> DOTNET

* Fix filenames

* Missing >

* Missing quotes

* use %scriptPath%

* Rework properties, start two examples

* Arch demo

* Cleanup

* Remove tab

* Easier environment variables.  Undo precommand changes.

* undo blank line

* clean CHECKs

* Draft of bash

* Bash, conditionals

* More variables, start on run.cmd/sh/py

* another output

* Support in cmd/bash for RunningDisasmChecks

* copy, factor, formatting

* Initial work to include FileCheck. Added SuperFileCheck.

* Able to build SuperFileCheck

* Do not DisasmCheck TypeEquality_r for now. Update some FileChecks to follow SuperFileCheck rules.

* Partially wiring up SuperFileCheck to tests

* Piping list of method names from SuperFileCheck to JitDisasm

* Handling bash a little bit

* Moving SuperFileCheck to tests/Common

* Few tweaks

* Building SuperFileCheck as part of the test build

* Tweaking a few things

* Fixed a bug

* Moving SuperFileCheck back to src\coreclr\tools. Removed checks from TypeEquality_r.

* Restore original logic in Runtime_73681

* Trying to add CI leg for disasmchecks

* Use x64 package if x86 platform detected for JIT tools package

* Remove innerloop for disasmchecks

* Trying to fix build. Only run in Windows for now.

* Update Runtime_73681.cs

Trying to fail test

* Trying to fix build

* Update Runtime_73681.cs

* Update Runtime_73681.cs

* Fixing a few issues

* Trying to run disasmchecks as part of CI

* Trying to run disasmchecks

* Trying to run disasmchecks

* Trying to run disasmchecks

* Revert a change

* Trying to run disasmchecks

* Trying to run disasmchecks

* build SuperFileCheck on non-windows

* few tweaks

* Trying to fix CI

* Including SuperFileCheck for tests

* Cleanup

* More cleanup

* Cleanup

* Changed SuperFileCheck to not publish everything. Changed SuperFileCheck's lookup for FileCheck.

* Invoking SuperFileCheck using dotnet

* Making the test pass

* Only run disasm checks for coreclr and not mono

* Using HasBatchDisasmCheck and HasBashDisasmCheck to determine to run the check

* Enabling filecheck on linux and osx

* Added more comments

* Added ARM64 specific test. Do not run SuperFileCheck if no methods were found.

* Added documentation. Changed disasm-output.

* Minor doc tweak

* Minor doc tweak

* Minor doc tweak

* Minor doc tweak

* Minor doc tweak

* Cleanup. Trying to fix linux

* Fixing test

* Add information on additional functionality

* cleanup

* Add FileCheck snippet

* Undo environment variable changes

* Feedback from Mark

* Cleanup

* Trying to fix linux test run

* Trying to fix linux test run

* A few missing changes from the original branch

* Enable OSX for disasm checks

* cleanup / comment

* Force test failure

* Update Runtime_73681.cs

* Set env vars after errorlevel check

* Reverting back on setting environment variables in test. Added new FileCheck test for mod optimization

* Force a failure by changing the register

* Ignore native binaries for superpmi collect

* Update Runtime_34937.cs

* Force the correct failure

* Update Runtime_34937.cs

* Update Runtime_34937.cs

* Adding specific OS check prefixes. Changed dump-input context amount

* Added getting fully qualified method names with wildcards for SuperFileCheck

* More tests. Fixed a few issues with generics.

* Disabling generic support

* Error if it cannot find enclosing type declaration

* Fixing build

* Remove namespac

* Bring generics back, but in a limited form
Co-authored-by: NMark Plesko <markples@microsoft.com>
上级 2f8c0ebd
# Disassembly output verification checks
There are tests that the runtime executes that will be able to verify X64/ARM64 assembly output from the JIT.
The tools used to accomplish this are LLVM FileCheck, SuperFileCheck, and the JIT's ability to output disassembly using `DOTNET_JitDisasm`. LLVM FileCheck is built in https://www.github.com/dotnet/llvm-project and provides several packages for the various platforms. See more about LLVM FileCheck and its syntax here: https://llvm.org/docs/CommandGuide/FileCheck.html. SuperFileCheck is a custom tool located in https://www.github.com/dotnet/runtime. It wraps LLVM FileCheck and provides a simplified workflow for writing these tests in a C# file by leveraging Roslyn's syntax tree APIs.
# What is FileCheck?
From https://www.llvm.org/docs/CommandGuide/FileCheck.html:
> **FileCheck** reads two files (one from standard input, and one specified on the command line) and uses one
to verify the other. This behavior is particularly useful for the testsuite, which wants to verify that the
output of some tool (e.g. **llc**) contains the expected information (for example, a movsd from esp or
whatever is interesting). This is similar to using **grep**, but it is optimized for matching multiple
different inputs in one file in a specific order.
# Converting an existing test to use disassembly checking
We will use the existing test `JIT\Regression\JitBlue\Runtime_33972` as an example. The test's intent is to verify that on ARM64, the method `AdvSimd.CompareEqual` behaves correctly when a zero vector is passed as the second argument. Below are snippets of its use:
```csharp
static Vector64<byte> AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64<byte> left)
{
return AdvSimd.CompareEqual(left, Vector64<byte>.Zero);
}
...
...
if (!ValidateResult_Vector64<byte>(AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64<byte>.Zero), Byte.MaxValue))
result = -1;
```
Currently, the test only verifies that the behavior is correct. It does not verify that the optimal ARM64 instruction was actually used. So now we will add this verification.
First we need to modify the project file `Runtime_33972.csproj`:
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>
```
Looking at the `ItemGroup`:
```xml
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
```
We want to add `<HasDisasmCheck>true</HasDisasmCheck>` as a child of the `Compile` tag:
```xml
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
</ItemGroup>
```
Doing this lets the test builder and runner know that this test has assembly that needs to be verified. Finally, we need to write the assembly check and put the `[MethodImpl(MethodImplOptions.NoInlining)]` attribute on the method `AdvSimd_CompareEqual_Vector64_Byte_Zero`:
```csharp
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<byte> AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64<byte> left)
{
// ARM64-FULL-LINE: cmeq v0.8b, v0.8b, #0
return AdvSimd.CompareEqual(left, Vector64<byte>.Zero);
}
```
And that is it. A few notes about the above example:
- `ARM64-FULL-LINE` checks to see if there is an exact line that matches the disassembly output of the method `AdvSimd_CompareEqual_Vector64_Byte_Zero` - leading and trailing spaces are ignored.
- Method bodies that have FileCheck syntax, e.g. `ARM64-FULL-LINE:`/`X64:`/etc, must have the attribute `[MethodImpl(MethodImplOptions.NoInlining)]`. If it does not, then an error is reported.
- FileCheck syntax outside of a method body will also report an error.
# Additional functionality
LLVM has a different setup where each test file is passed to `lit`, and `RUN:` lines inside the test specify
configuration details such as architectures to run, FileCheck prefixes to use, etc. In our case, the build
files handle a lot of this with build conditionals and `.cmd`/`.sh` file generation. Additionally, LLVM tests
rely on the order of the compiler output corresponding to the order of the input functions in the test file.
When running under the JIT, the compilation order is dependent on execution, not the source order.
Functionality that has been added or moved to MSBuild:
- Conditionals controlling test execution
- Automatic specificiation of `CHECK` and `<architecture>` as check prefixes
Functionality that has been added or moved to SuperFileCheck:
- Each function is run under a separate invocation of FileCheck. SuperFileCheck adds additional `CHECK` lines
that search for the beginning and end of the output for each function. This ensures that output from
different functions don't contaminate each other. The separate invocations remove any dependency on the
order of the functions.
- `<check-prefix>-FULL-LINE:` - same as using FileCheck's `<check-prefix>:`, but checks that the line matches exactly; leading and trailing whitespace is ignored.
- `<check-prefix>-FULL-LINE-NEXT:` - same as using FileCheck's `<check-prefix>-NEXT:`, but checks that the line matches exactly; leading and trailing whitespace is ignored.
......@@ -313,6 +313,8 @@
<ProjectToBuild Condition="'$(NativeAotSupported)' == 'true' and '$(TargetArchitecture)' != '$(BuildArchitecture)'" Include="$(CoreClrProjectRoot)tools\aot\ILCompiler\ILCompiler_crossarch.csproj" Category="clr" />
<ProjectToBuild Condition="'$(TargetArchitecture)' != '$(BuildArchitecture)'" Include="$(CoreClrProjectRoot)tools\aot\crossgen2\crossgen2_crossarch.csproj" Category="clr" />
<ProjectToBuild Condition="'$(TargetOS)' == 'windows' or ('$(TargetOS)' == 'Linux' and ('$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64')) or '$(TargetOS)' == 'OSX'" Include="$(CoreClrProjectRoot)tools\SuperFileCheck\SuperFileCheck.csproj" Category="clr" />
</ItemGroup>
<ItemGroup Condition="$(_subset.Contains('+clr.toolstests+'))">
......
......@@ -48,6 +48,38 @@
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>8688ea2538ef1287c6619d35a26b5750d355cc18</Sha>
</Dependency>
<Dependency Name="runtime.linux-arm64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.linux-x64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.linux-musl-x64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>754d13817d834b716d339183e21aac7d2489c496</Sha>
</Dependency>
<Dependency Name="runtime.win-arm64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.win-x64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.osx.11.0-arm64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="runtime.osx.10.12-x64.Microsoft.NETCore.Runtime.JIT.Tools" Version="1.0.0-alpha.1.22431.4">
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>c1304304028d603e34f6803b0740c34441f80d2e</Sha>
</Dependency>
<Dependency Name="System.CommandLine" Version="2.0.0-beta4.22355.1">
<Uri>https://github.com/dotnet/command-line-api</Uri>
<Sha>5618b2d243ccdeb5c7e50a298b33b13036b4351b</Sha>
......
......@@ -204,5 +204,14 @@
<SwixPackageVersion>1.1.87-gba258badda</SwixPackageVersion>
<WixPackageVersion>1.0.0-v3.14.0.5722</WixPackageVersion>
<MonoWorkloadManifestVersion>6.0.0-preview.5.21275.7</MonoWorkloadManifestVersion>
<!-- JIT Tools -->
<runtimelinuxarm64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimelinuxarm64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimelinuxx64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimelinuxx64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimelinuxmuslarm64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimelinuxmuslarm64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimelinuxmuslx64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimelinuxmuslx64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimewinarm64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimewinarm64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimewinx64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimewinx64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimeosx110arm64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimeosx110arm64MicrosoftNETCoreRuntimeJITToolsVersion>
<runtimeosx1012x64MicrosoftNETCoreRuntimeJITToolsVersion>1.0.0-alpha.1.22431.4</runtimeosx1012x64MicrosoftNETCoreRuntimeJITToolsVersion>
</PropertyGroup>
</Project>
......@@ -168,6 +168,9 @@ native_binaries_to_ignore = [
"vcruntime140_1.dll",
"R2RDump.exe",
"R2RTest.exe",
"FileCheck.exe",
"SuperFileCheck.exe",
"llvm-mca.exe",
"superpmi.exe",
"superpmi-shim-collector.dll",
"superpmi-shim-counter.dll",
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace SuperFileCheck
{
internal readonly record struct MethodDeclarationInfo(MethodDeclarationSyntax Syntax, string FullyQualifiedName);
internal readonly record struct FileCheckResult(int ExitCode, string StandardOutput, string StandardError);
internal class SuperFileCheckException : Exception
{
public SuperFileCheckException(string message): base(message) { }
}
internal class Program
{
const string CommandLineArgumentCSharp = "--csharp";
const string CommandLineArgumentCSharpListMethodNames = "--csharp-list-method-names";
const string CommandLineCheckPrefixes = "--check-prefixes";
const string CommandLineCheckPrefixesEqual = "--check-prefixes=";
const string CommandLineInputFile = "--input-file";
const string SyntaxDirectiveFullLine = "-FULL-LINE:";
const string SyntaxDirectiveFullLineNext = "-FULL-LINE-NEXT:";
static string FileCheckPath;
static Program()
{
// Determine the location of LLVM FileCheck.
// We first look through the "runtimes" directory relative to
// the location of SuperFileCheck to find FileCheck.
// If it cannot find it, then we assume FileCheck
// is in the same directory as SuperFileCheck.
var superFileCheckPath = typeof(Program).Assembly.Location;
if (String.IsNullOrEmpty(superFileCheckPath))
{
throw new SuperFileCheckException("Invalid SuperFileCheck path.");
}
var superFileCheckDir = Path.GetDirectoryName(superFileCheckPath);
if (superFileCheckDir != null)
{
var fileCheckPath =
Directory.EnumerateFiles(Path.Combine(superFileCheckDir, "runtimes/"), "FileCheck*", SearchOption.AllDirectories)
.FirstOrDefault();
if (fileCheckPath != null)
{
FileCheckPath = fileCheckPath;
}
else
{
FileCheckPath = Path.Combine(superFileCheckDir, "FileCheck");
}
}
else
{
FileCheckPath = "FileCheck";
}
}
/// <summary>
/// Checks if the given string contains LLVM "<prefix>" directives, such as "<prefix>:", "<prefix>-LABEL:", etc..
/// </summary>
static bool ContainsCheckPrefixes(string str, string[] checkPrefixes)
{
// LABEL, NOT, SAME, etc. are from LLVM FileCheck https://llvm.org/docs/CommandGuide/FileCheck.html
// FULL-LINE and FULL-LINE-NEXT are not part of LLVM FileCheck - they are new syntax directives for SuperFileCheck to be able to
// match a single full-line, similar to that of LLVM FileCheck's --match-full-lines option.
var pattern = $"({String.Join('|', checkPrefixes)})+?({{LITERAL}})?(:|-LABEL:|-NEXT:|-NOT:|-SAME:|-EMPTY:|-COUNT:|-DAG:|{SyntaxDirectiveFullLine}|{SyntaxDirectiveFullLineNext})";
var regex = new System.Text.RegularExpressions.Regex(pattern);
return regex.Count(str) > 0;
}
/// <summary>
/// Runs LLVM's FileCheck executable.
/// Will always redirect standard error and output.
/// </summary>
static async Task<FileCheckResult> RunLLVMFileCheckAsync(string[] args)
{
var startInfo = new ProcessStartInfo();
startInfo.FileName = FileCheckPath;
startInfo.Arguments = String.Join(' ', args);
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
try
{
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
using (var proc = Process.Start(startInfo))
{
if (proc == null)
{
return new FileCheckResult(1, String.Empty, String.Empty);
}
var stdOut = new StringBuilder();
var stdErr = new StringBuilder();
proc.OutputDataReceived += (_, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
stdOut.AppendLine(e.Data);
}
};
proc.ErrorDataReceived += (_, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
stdErr.AppendLine(e.Data);
}
};
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
await proc.WaitForExitAsync();
outputWaitHandle.WaitOne();
errorWaitHandle.WaitOne();
var exitCode = proc.ExitCode;
return new FileCheckResult(exitCode, stdOut.ToString(), stdErr.ToString());
}
}
catch (Exception ex)
{
return new FileCheckResult(1, String.Empty, ex.Message);
}
}
/// <summary>
/// Get the method name from the method declaration.
/// </summary>
static string GetMethodName(MethodDeclarationSyntax methodDecl)
{
var methodName = methodDecl.Identifier.ValueText;
var typeArity = methodDecl.TypeParameterList?.ChildNodes().Count();
if (typeArity > 0)
{
methodName = $"{methodName}[*]";
}
return $"{methodName}(*)";
}
/// <summary>
/// Get the enclosing type declaration syntax of the given node.
/// Errors if it cannot find one.
/// </summary>
static TypeDeclarationSyntax GetEnclosingTypeDeclaration(SyntaxNode node)
{
var typeDecl = node.Ancestors().OfType<TypeDeclarationSyntax>().FirstOrDefault();
if (typeDecl == null)
{
throw new SuperFileCheckException($"Unable to find enclosing type declaration on: {node.Span}");
}
return typeDecl;
}
/// <summary>
/// Get all the acestoral enclosing type declaration syntaxes of the given node.
/// </summary>
static TypeDeclarationSyntax[] GetEnclosingTypeDeclarations(SyntaxNode node)
{
return node.Ancestors().OfType<TypeDeclarationSyntax>().ToArray();
}
/// <summary>
/// Try to get an enclosing type name from the given syntax node.
/// </summary>
static string GetTypeName(TypeDeclarationSyntax typeDecl)
{
var typeName = typeDecl.Identifier.ValueText;
var typeArity = typeDecl.TypeParameterList?.ChildNodes().Count();
if (typeArity > 0)
{
typeName = $"{typeName}`{typeArity}[*]";
}
return typeName;
}
/// <summary>
/// Get the method's fully qualified enclosing namespace and type name.
/// </summary>
static string GetFullyQualifiedEnclosingTypeName(MethodDeclarationSyntax methodDecl)
{
var qualifiedTypeName = String.Empty;
var typeDecl = GetEnclosingTypeDeclaration(methodDecl);
qualifiedTypeName = GetTypeName(typeDecl);
var typeDecls = GetEnclosingTypeDeclarations(typeDecl);
for (var i = 0; i < typeDecls.Length; i++)
{
typeDecl = typeDecls[i];
qualifiedTypeName = $"{GetTypeName(typeDecl)}+{qualifiedTypeName}";
}
var namespaceDecl = typeDecl.Ancestors().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();
if (namespaceDecl != null)
{
var identifiers =
namespaceDecl.DescendantTokens().Where(x => x.IsKind(SyntaxKind.IdentifierToken)).Select(x => x.ValueText);
return $"{String.Join(".", identifiers)}.{qualifiedTypeName}";
}
return qualifiedTypeName;
}
/// <summary>
/// Get all the descendant single line comment trivia items.
/// </summary>
static IEnumerable<SyntaxTrivia> GetDescendantSingleLineCommentTrivia(SyntaxNode node)
{
return
node
.DescendantTrivia()
.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia));
}
/// <summary>
/// Gather all syntactical method declarations whose body contains
/// FileCheck syntax.
/// </summary>
static MethodDeclarationInfo[] FindMethodsByFile(string filePath, string[] checkPrefixes)
{
var syntaxTree = CSharpSyntaxTree.ParseText(SourceText.From(File.ReadAllText(filePath)));
var root = syntaxTree.GetRoot();
var trivia =
GetDescendantSingleLineCommentTrivia(root)
.Where(x =>
{
if (x.Token.Parent == null)
{
return true;
}
// A comment before the method declaration is considered a child of the method
// declaration. In this example:
//
// // trivia1
// public void M()
// {
// // trivia2
// }
//
// Both // trivia1 and // trivia2 are descendants of MethodDeclarationSyntax.
//
// We are only allowing checks to occur in 'trivia2'. The 'Contains' check is
// used to find 'trivia1'.
return !x.Token.Parent.Ancestors().Any(p => p.IsKind(SyntaxKind.MethodDeclaration) && p.Span.Contains(x.Span));
})
.Where(x => ContainsCheckPrefixes(x.ToString(), checkPrefixes))
.ToArray();
if (trivia.Length > 0)
{
throw new SuperFileCheckException("FileCheck syntax not allowed outside of a method.");
}
return
root
.DescendantNodes()
.OfType<MethodDeclarationSyntax>()
.Where(x => ContainsCheckPrefixes(x.ToString(), checkPrefixes))
.Select(x => new MethodDeclarationInfo(x, $"{GetFullyQualifiedEnclosingTypeName(x)}:{GetMethodName(x)}"))
.ToArray();
}
/// <summary>
/// Helper to expand FileCheck syntax.
/// </summary>
static string? TryTransformDirective(string lineStr, string[] checkPrefixes, string syntaxDirective, string transformSuffix)
{
var index = lineStr.IndexOf(syntaxDirective);
if (index == -1)
{
return null;
}
var prefix = lineStr.Substring(0, index);
// Do not transform if the prefix is not part of --check-prefixes.
if (!checkPrefixes.Any(x => prefix.EndsWith(x)))
{
return null;
}
return lineStr.Substring(0, index) + $"{transformSuffix}: {{{{^ *}}}}" + lineStr.Substring(index + syntaxDirective.Length) + "{{$}}";
}
/// <summary>
/// Will try to transform a line containing custom SuperFileCheck syntax, e.g. "CHECK-FULL-LINE:"
/// to the appropriate FileCheck syntax.
/// </summary>
static string TransformLine(TextLine line, string[] checkPrefixes)
{
var text = line.Text;
if (text == null)
{
throw new InvalidOperationException("SourceText is null.");
}
var lineStr = text.ToString(line.Span);
var result = TryTransformDirective(lineStr, checkPrefixes, SyntaxDirectiveFullLine, String.Empty);
if (result != null)
{
return result;
}
result = TryTransformDirective(lineStr, checkPrefixes, SyntaxDirectiveFullLineNext, "-NEXT");
return result ?? lineStr;
}
/// <summary>
/// Will try to transform a method containing custom SuperFileCheck syntax, e.g. "CHECK-FULL-LINE:"
/// to the appropriate FileCheck syntax.
/// </summary>
static string TransformMethod(MethodDeclarationSyntax methodDecl, string[] checkPrefixes)
{
return String.Join(Environment.NewLine, methodDecl.GetText().Lines.Select(x => TransformLine(x, checkPrefixes)));
}
/// <summary>
/// Gets the starting line number of the method declaration.
/// </summary>
static int GetMethodStartingLineNumber(MethodDeclarationSyntax methodDecl)
{
var leadingTrivia = methodDecl.GetLeadingTrivia();
if (leadingTrivia.Count == 0)
{
return methodDecl.GetLocation().GetLineSpan().StartLinePosition.Line;
}
else
{
return leadingTrivia[0].GetLocation().GetLineSpan().StartLinePosition.Line;
}
}
/// <summary>
/// Returns only the method declaration text along with any SuperFileCheck transformations.
/// </summary>
static string PreProcessMethod(MethodDeclarationInfo methodDeclInfo, string[] checkPrefixes)
{
var methodDecl = methodDeclInfo.Syntax;
var methodName = methodDeclInfo.FullyQualifiedName.Replace("*", "{{.*}}"); // Change wild-card to FileCheck wild-card syntax.
// Create anchors from the first prefix.
var startAnchorText = $"// {checkPrefixes[0]}-LABEL: {methodName}";
var endAnchorText = $"// {checkPrefixes[0]}: {methodName}";
// Create temp source file based on the source text of the method.
// Newlines are added to pad the text so FileCheck's error messages will correspond
// to the correct line and column of the original source file.
// This is not perfect but will work for most cases.
var lineNumber = GetMethodStartingLineNumber(methodDecl);
var tmpSrc = new StringBuilder();
for (var i = 1; i < lineNumber; i++)
{
tmpSrc.AppendLine(String.Empty);
}
tmpSrc.AppendLine(startAnchorText);
tmpSrc.AppendLine(TransformMethod(methodDecl, checkPrefixes));
tmpSrc.AppendLine(endAnchorText);
return tmpSrc.ToString();
}
/// <summary>
/// Runs SuperFileCheck logic.
/// </summary>
static async Task<FileCheckResult> RunSuperFileCheckAsync(MethodDeclarationInfo methodDeclInfo, string[] args, string[] checkPrefixes, string tmpFilePath)
{
File.WriteAllText(tmpFilePath, PreProcessMethod(methodDeclInfo, checkPrefixes));
try
{
args[0] = tmpFilePath;
return await RunLLVMFileCheckAsync(args);
}
finally
{
try { File.Delete(tmpFilePath); } catch { }
}
}
/// <summary>
/// Checks if the argument is --csharp.
/// </summary>
static bool IsArgumentCSharp(string arg)
{
return arg.Equals(CommandLineArgumentCSharp);
}
/// <summary>
/// Checks if the argument is --csharp-list-method-names.
/// </summary>
static bool IsArgumentCSharpListMethodNames(string arg)
{
return arg.Equals(CommandLineArgumentCSharpListMethodNames);
}
/// <summary>
/// Checks if the argument contains -h.
/// </summary>
static bool ArgumentsContainHelp(string[] args)
{
return args.Any(x => x.Contains("-h"));
}
/// <summary>
/// From the given arguments, find the first --check-prefixes argument and parse its value
/// in the form of an array.
/// </summary>
static string[] ParseCheckPrefixes(string[] args)
{
var checkPrefixesArg = args.FirstOrDefault(x => x.StartsWith(CommandLineCheckPrefixesEqual));
if (checkPrefixesArg == null)
{
return new string[] { };
}
return
checkPrefixesArg
.Replace(CommandLineCheckPrefixesEqual, "")
.Split(",")
.Where(x => !String.IsNullOrWhiteSpace(x))
.ToArray();
}
/// <summary>
/// Will always return one or more prefixes.
/// </summary>
static string[] DetermineCheckPrefixes(string[] args)
{
var checkPrefixes = ParseCheckPrefixes(args);
if (checkPrefixes.Length == 0)
{
// FileCheck's default.
return new string[] { "CHECK" };
}
return checkPrefixes;
}
/// <summary>
/// Prints error expecting a CSharp file.
/// </summary>
static void PrintErrorExpectedCSharpFile()
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Expected C# file.");
Console.ResetColor();
}
/// <summary>
/// Prints error indicating a duplicate method name was found.
/// </summary>
static void PrintErrorDuplicateMethodName(string methodName)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"Duplicate method name found: {methodName}");
Console.ResetColor();
}
/// <summary>
/// Prints error indicating the method was not marked with attribute 'MethodImpl(MethodImplOptions.NoInlining)'.
/// </summary>
static void PrintErrorMethodNoInlining(string methodName)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"'{methodName}' is not marked with attribute 'MethodImpl(MethodImplOptions.NoInlining)'.");
Console.ResetColor();
}
/// <summary>
/// Prints error indicating that no methods were found to have any FileCheck syntax
/// of the given --check-prefixes.
/// </summary>
static void PrintErrorNoMethodsFound(string[] checkPrefixes)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("No methods were found. Check if any method bodies are using one or more of the following FileCheck prefixes:");
foreach (var prefix in checkPrefixes)
{
Console.Error.WriteLine($" {prefix}");
}
Console.ResetColor();
}
/// <summary>
/// Prints error indicating that a --input-file was not found.
/// </summary>
static void PrintErrorNoInputFileFound()
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"{CommandLineInputFile} is required.");
Console.ResetColor();
}
/// <summary>
/// Prints command line help.
/// </summary>
static void PrintHelp()
{
Console.Write(Environment.NewLine);
Console.WriteLine("USAGE: SuperFileCheck [options] <check-file>");
Console.WriteLine("USAGE: SuperFileCheck <super-option> <check-file> [options]");
Console.Write(Environment.NewLine);
Console.WriteLine("SUPER OPTIONS:");
Console.Write(Environment.NewLine);
Console.WriteLine($" --csharp - A {CommandLineInputFile} is required.");
Console.WriteLine($" <check-file> must be a C# source file.");
Console.WriteLine($" Methods must not have duplicate names.");
Console.WriteLine($" Methods must be marked as not inlining.");
Console.WriteLine($" One or more methods are required.");
Console.WriteLine($" Prefixes are determined by {CommandLineCheckPrefixes}.");
Console.WriteLine($" --csharp-list-method-names - Print a space-delimited list of method names to be");
Console.WriteLine($" supplied to environment variable DOTNET_JitDisasm.");
Console.WriteLine($" <check-file> must be a C# source file.");
Console.WriteLine($" Methods must not have duplicate names.");
Console.WriteLine($" Methods must be marked as not inlining.");
Console.WriteLine($" Prints nothing if no methods are found.");
Console.WriteLine($" Prefixes are determined by {CommandLineCheckPrefixes}.");
}
/// <summary>
/// Try to find the first duplicate method name of the given method declarations.
/// </summary>
static string? TryFindDuplicateMethodName(MethodDeclarationInfo[] methodDeclInfos)
{
var set = new HashSet<string>();
var duplicateMethodDeclInfo =
methodDeclInfos.FirstOrDefault(x => !set.Add(x.FullyQualifiedName));
return duplicateMethodDeclInfo.FullyQualifiedName;
}
/// <summary>
/// Is the method marked with MethodImpl(MethodImplOptions.NoInlining)?
/// </summary>
static bool MethodHasNoInlining(MethodDeclarationSyntax methodDecl)
{
return methodDecl.AttributeLists.ToString().Contains("MethodImplOptions.NoInlining");
}
/// <summary>
/// Will print an error if any duplicate method names are found.
/// </summary>
static bool CheckDuplicateMethodNames(MethodDeclarationInfo[] methodDeclInfos)
{
var duplicateMethodName = TryFindDuplicateMethodName(methodDeclInfos);
if (duplicateMethodName != null)
{
PrintErrorDuplicateMethodName(duplicateMethodName);
return false;
}
return true;
}
/// <summary>
/// Will print an error if the methods containing FileCheck syntax
/// is not marked with the attribute 'MethodImpl(MethodImplOptions.NoInlining)'.
/// </summary>
static bool CheckMethodsHaveNoInlining(MethodDeclarationInfo[] methodDeclInfos)
{
return
methodDeclInfos
.All(methodDeclInfo =>
{
if (!MethodHasNoInlining(methodDeclInfo.Syntax))
{
PrintErrorMethodNoInlining(methodDeclInfo.FullyQualifiedName);
return false;
}
return true;
});
}
/// <summary>
/// The goal of SuperFileCheck is to make writing LLVM FileCheck tests against the
/// NET Core Runtime easier in C#.
/// </summary>
static async Task<int> Main(string[] args)
{
if (args.Length >= 1)
{
if (IsArgumentCSharpListMethodNames(args[0]))
{
if (args.Length == 1)
{
PrintErrorExpectedCSharpFile();
return 1;
}
var checkPrefixes = DetermineCheckPrefixes(args);
try
{
var methodDeclInfos = FindMethodsByFile(args[1], checkPrefixes);
if (methodDeclInfos.Length == 0)
{
return 0;
}
if (!CheckDuplicateMethodNames(methodDeclInfos))
{
return 1;
}
Console.Write(String.Join(' ', methodDeclInfos.Select(x => x.FullyQualifiedName)));
return 0;
}
catch(Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
return 1;
}
}
if (IsArgumentCSharp(args[0]))
{
if (args.Length == 1)
{
PrintErrorExpectedCSharpFile();
return 1;
}
var checkFilePath = args[1];
var checkFileNameNoExt = Path.GetFileNameWithoutExtension(checkFilePath);
var hasInputFile = args.Any(x => x.Equals(CommandLineInputFile));
if (!hasInputFile)
{
PrintErrorNoInputFileFound();
return 1;
}
var checkPrefixes = DetermineCheckPrefixes(args);
try
{
var methodDeclInfos = FindMethodsByFile(checkFilePath, checkPrefixes);
if (!CheckDuplicateMethodNames(methodDeclInfos))
{
return 1;
}
if (!CheckMethodsHaveNoInlining(methodDeclInfos))
{
return 1;
}
if (methodDeclInfos.Length > 0)
{
var didSucceed = true;
var tasks = new Task<FileCheckResult>[methodDeclInfos.Length];
// Remove the first 'csharp' argument so we can pass the rest of the args
// to LLVM FileCheck.
var argsToCopy = args.AsSpan(1).ToArray();
for (int i = 0; i < methodDeclInfos.Length; i++)
{
var index = i;
var tmpFileName = $"__tmp{index}_{checkFileNameNoExt}.cs";
var tmpDirName = Path.GetDirectoryName(checkFilePath);
string tmpFilePath;
if (String.IsNullOrWhiteSpace(tmpDirName))
{
tmpFilePath = tmpFileName;
}
else
{
tmpFilePath = Path.Combine(tmpDirName, tmpFileName);
}
tasks[i] = Task.Run(() => RunSuperFileCheckAsync(methodDeclInfos[index], argsToCopy.ToArray(), checkPrefixes, tmpFilePath));
}
await Task.WhenAll(tasks);
foreach (var x in tasks)
{
if (x.Result.ExitCode != 0)
{
didSucceed = false;
}
Console.Write(x.Result.StandardOutput);
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.Write(x.Result.StandardError);
Console.ResetColor();
}
return didSucceed ? 0 : 1;
}
else
{
PrintErrorNoMethodsFound(checkPrefixes);
return 1;
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
return 1;
}
}
}
var result = await RunLLVMFileCheckAsync(args);
Console.Write(result.StandardOutput);
if (ArgumentsContainHelp(args))
{
PrintHelp();
}
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.Write(result.StandardError);
Console.ResetColor();
return result.ExitCode;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>SuperFileCheck</AssemblyName>
<OutputType>Exe</OutputType>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<PlatformTarget>AnyCPU</PlatformTarget>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendTargetFrameworkToOutputPath Condition="'$(BuildingInsideVisualStudio)' == 'true'">true</AppendTargetFrameworkToOutputPath>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputPath>$(RuntimeBinDir)\SuperFileCheck</OutputPath>
</PropertyGroup>
<PropertyGroup>
<!-- Massage the OutputRid into an JITTools package RID that we can download -->
<_jitToolsRidPlatformIndex>$(OutputRid.LastIndexOf('-'))</_jitToolsRidPlatformIndex>
<JITToolsRidWithoutPlatform>$(OutputRid.Substring(0, $(_jitToolsRidPlatformIndex)))</JITToolsRidWithoutPlatform>
<JITToolsRidPlatform>$(OutputRid.Substring($(_jitToolsRidPlatformIndex)).TrimStart('-'))</JITToolsRidPlatform>
<!-- If it's not win/osx/linux-musl, it's a non-portable Linux. Treat as Linux. -->
<JITToolsRidWithoutPlatform Condition="'$(JITToolsRidWithoutPlatform)' != 'win' and '$(JITToolsRidWithoutPlatform)' != 'osx' and '$(JITToolsRidWithoutPlatform)' != 'linux-musl'">linux</JITToolsRidWithoutPlatform>
<!-- OSX builds have a version -->
<JITToolsRidWithoutPlatform Condition="'$(JITToolsRidWithoutPlatform)' == 'osx' and '$(JITToolsRidPlatform)' == 'x64'">osx.10.12</JITToolsRidWithoutPlatform>
<JITToolsRidWithoutPlatform Condition="'$(JITToolsRidWithoutPlatform)' == 'osx' and '$(JITToolsRidPlatform)' == 'arm64'">osx.11.0</JITToolsRidWithoutPlatform>
<!-- There are no x86 packages, so use x64 -->
<JITToolsRidPlatform Condition="'$(JITToolsRidPlatform)' == 'x86'">x64</JITToolsRidPlatform>
<JITToolsRidPlatform Condition="'$(JITToolsRidPlatform)' == 'arm' and '$(JITToolsRidWithoutPlatform)' == 'win'">arm64</JITToolsRidPlatform>
<JITToolsRid Condition="'$(JITToolsRid)' == ''">$(JITToolsRidWithoutPlatform)-$(JITToolsRidPlatform)</JITToolsRid>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'linux-arm64'">$(runtimelinuxarm64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'linux-x64'">$(runtimelinuxx64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'linux-musl-arm64'">$(runtimelinuxmuslarm64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'linux-musl-x64'">$(runtimelinuxmuslx64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'win-arm64'">$(runtimewinarm64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'win-x64'">$(runtimewinx64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'osx.11.0-arm64'">$(runtimeosx110arm64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
<JITToolsVersion Condition="'$(JITToolsVersion)' == '' and '$(JITToolsRid)' == 'osx.10.12-x64'">$(runtimeosx1012x64MicrosoftNETCoreRuntimeJITToolsVersion)</JITToolsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisCSharpVersion)" />
<PackageReference Include="runtime.$(JITToolsRid).Microsoft.NETCore.Runtime.JIT.Tools">
<Version>$(JITToolsVersion)</Version>
</PackageReference>
</ItemGroup>
</Project>
......@@ -430,8 +430,13 @@ echo /usr/bin/env bash $(InputAssemblyName) %24(printf "'%s' " "${CLRTestExecuti
CLRTestExitCode=$?
CLRTestExpectedExitCode=0
]]></BashCLRTestLaunchCmds>
</PropertyGroup>
<BashCLRTestPostCommands><![CDATA[
$(BashDisasmCheckPostCommands)
$(CLRTestBashPostCommands)
]]></BashCLRTestPostCommands>
</PropertyGroup>
<PropertyGroup>
<BashEnvironmentVariables>
@(CLRTestBashEnvironmentVariable -> '%(Identity)', '%0a')
......
......@@ -301,6 +301,7 @@ $(BatchIlrtTestLaunchCmds)
if defined RunCrossGen2 (
call :TakeLock
)
ECHO %LAUNCHER% %ExePath% %CLRTestExecutionArguments%
%LAUNCHER% %ExePath% %CLRTestExecutionArguments%
set CLRTestExitCode=!ERRORLEVEL!
......@@ -338,6 +339,12 @@ cmd /c $(InputAssemblyName)
set CLRTestExitCode=!ERRORLEVEL!
set CLRTestExpectedExitCode=0
]]></BatchCLRTestLaunchCmds>
<BatchCLRTestPostCommands><![CDATA[
$(BatchDisasmCheckPostCommands)
$(CLRTestBatchPostCommands)
]]></BatchCLRTestPostCommands>
</PropertyGroup>
<PropertyGroup>
<BatchEnvironmentVariables>
......@@ -445,7 +452,7 @@ $(CLRTestBatchPreCommands)
REM Launch
$(BatchCLRTestLaunchCmds)
REM PostCommands
$(CLRTestBatchPostCommands)
$(BatchCLRTestPostCommands)
$(BatchCLRTestExitCodeCheck)
]]></_CLRTestExecutionScriptText>
</PropertyGroup>
......
......@@ -20,6 +20,11 @@ WARNING: When setting properties based on their current state (for example:
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BashScriptSnippetGen>$(BashScriptSnippetGen);GetIlasmRoundTripBashScript;GetDisasmCheckBashScript</BashScriptSnippetGen>
<BatchScriptSnippetGen>$(BatchScriptSnippetGen);GetIlasmRoundTripBatchScript;GetDisasmCheckBatchScript</BatchScriptSnippetGen>
</PropertyGroup>
<!--
***********************************************************************************************
ildasm / ilasm round trip testing
......@@ -187,6 +192,115 @@ IF NOT DEFINED DoLink (
</PropertyGroup>
</Target>
<Target Name="GetDisasmCheckData"
Returns="$(HasDisasmCheck);@(DisasmCheckFiles)">
<ItemGroup>
<DisasmCheckFiles Include="%(Compile.Identity)" Condition="'%(Compile.HasDisasmCheck)' == 'true'" />
</ItemGroup>
<PropertyGroup>
<HasDisasmCheck>false</HasDisasmCheck>
<HasDisasmCheck Condition="@(DisasmCheckFiles->Count()) &gt; 0 And '$(CLRTestKind)' == 'BuildAndRun'">true</HasDisasmCheck>
</PropertyGroup>
</Target>
<!--
The source code file(s) (specified by HasDisasmCheck in the test's project file) contain
the patterns used by FileCheck. They need to be copied to the output directory for the
test to be self-contained.
-->
<Target Name="PropagateHasDisasmCheckToCopy"
BeforeTargets="AssignTargetPaths">
<ItemGroup>
<Compile Update="@(Compile)"
Condition="'%(Compile.HasDisasmCheck)' == 'true'"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Target>
<Target Name="GetDisasmCheckBashScript"
Returns="$(HasBashDisasmCheck);$(BashDisasmOutputFile);$(BashDisasmCheckPostCommands)"
DependsOnTargets="GetDisasmCheckData">
<PropertyGroup>
<HasBashDisasmCheck>false</HasBashDisasmCheck>
<HasBashDisasmCheck Condition="'$(HasDisasmCheck)' == 'true' and '$(RuntimeFlavor)' == 'coreclr' and ('$(TargetOS)' == 'Linux' or '$(TargetOS)' == 'OSX') and ('$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64')">true</HasBashDisasmCheck>
<BashDisasmOutputFile>/dev/null</BashDisasmOutputFile>
<BashDisasmOutputFile Condition="'$(HasBashDisasmCheck)' == 'true'">$(scriptPath)__jit_disasm.out</BashDisasmOutputFile>
<BashDisasmListOutputFile>/dev/null</BashDisasmListOutputFile>
<BashDisasmListOutputFile Condition="'$(HasBashDisasmCheck)' == 'true'">$(scriptPath)__jit_disasm_list.out</BashDisasmListOutputFile>
<BashCLRTestPreCommands Condition="'$(HasBashDisasmCheck)' == 'true'"><![CDATA[
@(DisasmCheckFiles -> ' dotnet $CORE_ROOT/SuperFileCheck/SuperFileCheck.dll --csharp-list-method-names "%(Identity)" --allow-unused-prefixes --check-prefixes=CHECK,$(TargetArchitecture.ToUpperInvariant()),$(TargetArchitecture.ToUpperInvariant())-$(TargetOS.ToUpperInvariant()) > "$(BashDisasmListOutputFile)"
ERRORLEVEL=$?
export COMPlus_JitDisasm=`cat $(BashDisasmListOutputFile)`
export COMPlus_JitDiffableDasm=1
export COMPlus_JitStdOutFile=$(BashDisasmOutputFile)
if [[ $ERRORLEVEL -ne 0 ]]
then
echo EXECUTION OF FILECHECK - FAILED $ERRORLEVEL
exit 1
fi', '%0a')
]]>
</BashCLRTestPreCommands>
<BashDisasmCheckPostCommands></BashDisasmCheckPostCommands>
<BashDisasmCheckPostCommands Condition="'$(HasBashDisasmCheck)' == 'true'"><![CDATA[
if [[ -n $COMPlus_JitDisasm ]]; then
@(DisasmCheckFiles -> ' dotnet $CORE_ROOT/SuperFileCheck/SuperFileCheck.dll --csharp "%(Identity)" --allow-unused-prefixes --check-prefixes=CHECK,$(TargetArchitecture.ToUpperInvariant()),$(TargetArchitecture.ToUpperInvariant())-$(TargetOS.ToUpperInvariant()) --dump-input-context 25 --input-file "$(BashDisasmOutputFile)"
ERRORLEVEL=$?
if [[ $ERRORLEVEL -ne 0 ]]
then
echo EXECUTION OF FILECHECK - FAILED $ERRORLEVEL
exit 1
fi', '%0a')
fi
]]>
</BashDisasmCheckPostCommands>
</PropertyGroup>
</Target>
<Target Name="GetDisasmCheckBatchScript"
Returns="$(HasBatchDisasmCheck);$(BatchDisasmOutputFile);$(BatchDisasmCheckPostCommands)"
DependsOnTargets="GetDisasmCheckData">
<PropertyGroup>
<HasBatchDisasmCheck>false</HasBatchDisasmCheck>
<HasBatchDisasmCheck Condition="'$(HasDisasmCheck)' == 'true' and '$(RuntimeFlavor)' == 'coreclr'">true</HasBatchDisasmCheck>
<BatchDisasmOutputFile>NUL</BatchDisasmOutputFile>
<BatchDisasmOutputFile Condition="'$(HasBatchDisasmCheck)' == 'true'">$(scriptPath)__jit_disasm.out</BatchDisasmOutputFile>
<BatchDisasmListOutputFile>NUL</BatchDisasmListOutputFile>
<BatchDisasmListOutputFile Condition="'$(HasBatchDisasmCheck)' == 'true'">$(scriptPath)__jit_disasm_list.out</BatchDisasmListOutputFile>
<CLRTestBatchPreCommands Condition="'$(HasBatchDisasmCheck)' == 'true'">
<![CDATA[
$(CLRTestBatchPreCommands)
@(DisasmCheckFiles -> ' dotnet %CORE_ROOT%\SuperFileCheck\SuperFileCheck.dll --csharp-list-method-names "%(Identity)" --check-prefixes=CHECK,$(TargetArchitecture.ToUpperInvariant()),$(TargetArchitecture.ToUpperInvariant())-$(TargetOS.ToUpperInvariant()) > "$(BatchDisasmListOutputFile)"
IF NOT "!ERRORLEVEL!" == "0" (
ECHO EXECUTION OF FILECHECK LISTING METHOD NAMES - FAILED !ERRORLEVEL!
Exit /b 1
)', '%0d%0a')
for /F "delims=" %%g in ($(BatchDisasmListOutputFile)) do set COMPlus_JitDisasm=%%g
set COMPlus_JitDiffableDasm=1
set COMPlus_JitStdOutFile=$(BatchDisasmOutputFile)
]]>
</CLRTestBatchPreCommands>
<BatchDisasmCheckPostCommands></BatchDisasmCheckPostCommands>
<BatchDisasmCheckPostCommands Condition="'$(HasBatchDisasmCheck)' == 'true'"><![CDATA[
IF NOT "%COMPlus_JitDisasm%" == "" (
@(DisasmCheckFiles -> ' dotnet %CORE_ROOT%\SuperFileCheck\SuperFileCheck.dll --csharp "%(Identity)" --allow-unused-prefixes --check-prefixes=CHECK,$(TargetArchitecture.ToUpperInvariant()),$(TargetArchitecture.ToUpperInvariant())-$(TargetOS.ToUpperInvariant()) --dump-input-context 25 --input-file "$(BatchDisasmOutputFile)"
IF NOT "!ERRORLEVEL!" == "0" (
ECHO EXECUTION OF FILECHECK - FAILED !ERRORLEVEL!
Exit /b 1
)', '%0d%0a')
)
]]>
</BatchDisasmCheckPostCommands>
</PropertyGroup>
</Target>
<!--
***********************************************************************************************
SuperPMI collection of CoreCLR tests
......
......@@ -87,6 +87,11 @@
<IncludeSubFolders>True</IncludeSubFolders>
</RunTimeArtifactsIncludeFolders>
<!-- Used by disasm output verification tests -->
<RunTimeArtifactsIncludeFolders Include="SuperFileCheck/">
<IncludeSubFolders>True</IncludeSubFolders>
</RunTimeArtifactsIncludeFolders>
<!-- XUnit runner harness assemblies that we don't want to mix in with the framework in Core_Root -->
<RunTimeArtifactsIncludeFolders Include="xunit/" />
</ItemGroup>
......
......@@ -383,6 +383,11 @@
<IncludeSubFolders>True</IncludeSubFolders>
</RunTimeArtifactsIncludeFolders>
<!-- Used by disasm output verification tests -->
<RunTimeArtifactsIncludeFolders Include="SuperFileCheck/">
<IncludeSubFolders>True</IncludeSubFolders>
</RunTimeArtifactsIncludeFolders>
<!-- XUnit runner harness assemblies that we don't want to mix in with the framework in Core_Root -->
<RunTimeArtifactsIncludeFolders Include="xunit/" />
</ItemGroup>
......
......@@ -8,143 +8,167 @@
class Program
{
// CompareEqual
// CompareEqual
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<byte> AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64<byte> left)
{
// ARM64-FULL-LINE: cmeq v0.8b, v0.8b, #0
return AdvSimd.CompareEqual(left, Vector64<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<sbyte> AdvSimd_CompareEqual_Vector64_SByte_Zero(Vector64<sbyte> left)
{
// ARM64-FULL-LINE: cmeq v0.8b, v0.8b, #0
return AdvSimd.CompareEqual(left, Vector64<sbyte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<ushort> AdvSimd_CompareEqual_Vector64_UInt16_Zero(Vector64<ushort> left)
{
// ARM64-FULL-LINE: cmeq v0.4h, v0.4h, #0
return AdvSimd.CompareEqual(left, Vector64<ushort>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<short> AdvSimd_CompareEqual_Vector64_Int16_Zero(Vector64<short> left)
{
// ARM64-FULL-LINE: cmeq v0.4h, v0.4h, #0
return AdvSimd.CompareEqual(left, Vector64<short>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<uint> AdvSimd_CompareEqual_Vector64_UInt32_Zero(Vector64<uint> left)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(left, Vector64<uint>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<int> AdvSimd_CompareEqual_Vector64_Int32_Zero(Vector64<int> left)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(left, Vector64<int>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareEqual_Vector64_Single_Zero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.2s, v0.2s, #0.0
return AdvSimd.CompareEqual(left, Vector64<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<int> AdvSimd_CompareEqual_Vector64_Int32_CreateZero(Vector64<int> left)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(left, Vector64.Create(0));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<int> AdvSimd_CompareEqual_Vector64_Int32_CreateZeroZero(Vector64<int> left)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(left, Vector64.Create(0, 0));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareEqual_Vector64_Single_CreateZero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.2s, v0.2s, #0.0
return AdvSimd.CompareEqual(left, Vector64.Create(0f));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareEqual_Vector64_Single_CreateZeroZero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.2s, v0.2s, #0.0
return AdvSimd.CompareEqual(left, Vector64.Create(0f, 0f));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<byte> AdvSimd_CompareEqual_Vector128_Byte_Zero(Vector128<byte> left)
{
// ARM64-FULL-LINE: cmeq v0.16b, v0.16b, #0
return AdvSimd.CompareEqual(left, Vector128<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<sbyte> AdvSimd_CompareEqual_Vector128_SByte_Zero(Vector128<sbyte> left)
{
// ARM64-FULL-LINE: cmeq v0.16b, v0.16b, #0
return AdvSimd.CompareEqual(left, Vector128<sbyte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<ushort> AdvSimd_CompareEqual_Vector128_UInt16_Zero(Vector128<ushort> left)
{
// ARM64-FULL-LINE: cmeq v0.8h, v0.8h, #0
return AdvSimd.CompareEqual(left, Vector128<ushort>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<short> AdvSimd_CompareEqual_Vector128_Int16_Zero(Vector128<short> left)
{
// ARM64-FULL-LINE: cmeq v0.8h, v0.8h, #0
return AdvSimd.CompareEqual(left, Vector128<short>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<uint> AdvSimd_CompareEqual_Vector128_UInt32_Zero(Vector128<uint> left)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(left, Vector128<uint>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<int> AdvSimd_CompareEqual_Vector128_Int32_Zero(Vector128<int> left)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(left, Vector128<int>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_Zero(Vector128<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.4s, v0.4s, #0.0
return AdvSimd.CompareEqual(left, Vector128<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<int> AdvSimd_CompareEqual_Vector128_Int32_CreateZero(Vector128<int> left)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(left, Vector128.Create(0));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<int> AdvSimd_CompareEqual_Vector128_Int32_CreateZeroZeroZeroZero(Vector128<int> left)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(left, Vector128.Create(0, 0, 0, 0));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_CreateZero(Vector128<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.4s, v0.4s, #0.0
return AdvSimd.CompareEqual(left, Vector128.Create(0f));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_CreateZeroZeroZeroZero(Vector128<float> left)
{
// ARM64-FULL-LINE: fcmeq v0.4s, v0.4s, #0.0
return AdvSimd.CompareEqual(left, Vector128.Create(0f, 0f, 0f, 0f));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_CreateZeroZeroZeroZero_AsVariable(Vector128<float> left)
{
// 'asVar' should be propagated.
// ARM64-FULL-LINE: fcmeq v0.4s, v0.4s, #0.0
var asVar = Vector128.Create(0f, 0f, 0f, 0f);
return AdvSimd.CompareEqual(left, asVar);
}
......@@ -154,12 +178,19 @@ static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_CreateZeroZeroZero
{
Vector128<float> result = default;
var asVar = Vector128.Create(0f, 0f, 0f, 0f);
// 'asVar' should be propagated.
// 'AdvSimd.CompareEqual' should be hoisted out of the loops.
// ARM64-FULL-LINE: fcmeq {{v[0-9]+}}.4s, {{v[0-9]+}}.4s, #0.0
// ARM64: blt
// ARM64-NOT: fcmeq
for (var i = 0; i < 4; i++)
{
result = AdvSimd.CompareEqual(left, asVar);
result = AdvSimd.CompareEqual(left, asVar);
result = AdvSimd.CompareEqual(left, asVar);
result = AdvSimd.CompareEqual(left, asVar);
// ARM64: blt
// ARM64-NOT: fcmeq
for (var j = 0; j < 4; j++)
{
result = AdvSimd.CompareEqual(left, asVar);
......@@ -178,9 +209,18 @@ static unsafe Vector128<long> AdvSimd_Arm64_CompareEqual_Vector128_Long_AsVariab
Vector128<long> asVar = Vector128.Create((long)0);
Vector128<nint> asVar2 = Vector128.Create((nint)0);
Vector128<long> asVar3 = asVar2.AsInt64();
// 'asVar' should be propagated.
// 'asVar2' should be propagated.
// 'asVar3' should be propagated.
// 'AdvSimd.CompareEqual' should be hoisted out of the loops.
// ARM64-FULL-LINE: cmeq {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, #0
// ARM64: blt
// ARM64-NOT: cmeq
for (var i = 0; i < 4; i++)
{
result = AdvSimd.Arm64.CompareEqual(left, asVar);
// ARM64: blt
// ARM64-NOT: cmeq
for (var j = 0; j < 4; j++)
{
result = AdvSimd.Arm64.CompareEqual(left, asVar3);
......@@ -192,42 +232,49 @@ static unsafe Vector128<long> AdvSimd_Arm64_CompareEqual_Vector128_Long_AsVariab
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<double> AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero(Vector128<double> left)
{
// ARM64-FULL-LINE: fcmeq v0.2d, v0.2d, #0.0
return AdvSimd.Arm64.CompareEqual(left, Vector128<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<ulong> AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero(Vector128<ulong> left)
{
// ARM64-FULL-LINE: cmeq v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareEqual(left, Vector128<ulong>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<long> AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero(Vector128<long> left)
{
// ARM64-FULL-LINE: cmeq v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareEqual(left, Vector128<long>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmeq s0, s0, #0.0
return AdvSimd.Arm64.CompareEqualScalar(left, Vector64<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<double> AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero(Vector64<double> left)
{
// ARM64-FULL-LINE: fcmeq d0, d0, #0.0
return AdvSimd.Arm64.CompareEqualScalar(left, Vector64<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<ulong> AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero(Vector64<ulong> left)
{
// ARM64-FULL-LINE: cmeq d0, d0, #0
return AdvSimd.Arm64.CompareEqualScalar(left, Vector64<ulong>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<long> AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero(Vector64<long> left)
{
// ARM64-FULL-LINE: cmeq d0, d0, #0
return AdvSimd.Arm64.CompareEqualScalar(left, Vector64<long>.Zero);
}
......@@ -236,126 +283,147 @@ static Vector64<long> AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero(Vecto
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<byte> AdvSimd_CompareEqual_Vector64_Byte_Zero_Swapped(Vector64<byte> right)
{
// ARM64-FULL-LINE: cmeq v0.8b, v0.8b, #0
return AdvSimd.CompareEqual(Vector64<byte>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<sbyte> AdvSimd_CompareEqual_Vector64_SByte_Zero_Swapped(Vector64<sbyte> right)
{
// ARM64-FULL-LINE: cmeq v0.8b, v0.8b, #0
return AdvSimd.CompareEqual(Vector64<sbyte>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<ushort> AdvSimd_CompareEqual_Vector64_UInt16_Zero_Swapped(Vector64<ushort> right)
{
// ARM64-FULL-LINE: cmeq v0.4h, v0.4h, #0
return AdvSimd.CompareEqual(Vector64<ushort>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<short> AdvSimd_CompareEqual_Vector64_Int16_Zero_Swapped(Vector64<short> right)
{
// ARM64-FULL-LINE: cmeq v0.4h, v0.4h, #0
return AdvSimd.CompareEqual(Vector64<short>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<uint> AdvSimd_CompareEqual_Vector64_UInt32_Zero_Swapped(Vector64<uint> right)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(Vector64<uint>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<int> AdvSimd_CompareEqual_Vector64_Int32_Zero_Swapped(Vector64<int> right)
{
// ARM64-FULL-LINE: cmeq v0.2s, v0.2s, #0
return AdvSimd.CompareEqual(Vector64<int>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareEqual_Vector64_Single_Zero_Swapped(Vector64<float> right)
{
// ARM64-FULL-LINE: fcmeq v0.2s, v0.2s, #0.0
return AdvSimd.CompareEqual(Vector64<float>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<byte> AdvSimd_CompareEqual_Vector128_Byte_Zero_Swapped(Vector128<byte> right)
{
// ARM64-FULL-LINE: cmeq v0.16b, v0.16b, #0
return AdvSimd.CompareEqual(Vector128<byte>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<sbyte> AdvSimd_CompareEqual_Vector128_SByte_Zero_Swapped(Vector128<sbyte> right)
{
// ARM64-FULL-LINE: cmeq v0.16b, v0.16b, #0
return AdvSimd.CompareEqual(Vector128<sbyte>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<ushort> AdvSimd_CompareEqual_Vector128_UInt16_Zero_Swapped(Vector128<ushort> right)
{
// ARM64-FULL-LINE: cmeq v0.8h, v0.8h, #0
return AdvSimd.CompareEqual(Vector128<ushort>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<short> AdvSimd_CompareEqual_Vector128_Int16_Zero_Swapped(Vector128<short> right)
{
// ARM64-FULL-LINE: cmeq v0.8h, v0.8h, #0
return AdvSimd.CompareEqual(Vector128<short>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<uint> AdvSimd_CompareEqual_Vector128_UInt32_Zero_Swapped(Vector128<uint> right)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(Vector128<uint>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<int> AdvSimd_CompareEqual_Vector128_Int32_Zero_Swapped(Vector128<int> right)
{
// ARM64-FULL-LINE: cmeq v0.4s, v0.4s, #0
return AdvSimd.CompareEqual(Vector128<int>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareEqual_Vector128_Single_Zero_Swapped(Vector128<float> right)
{
// ARM64-FULL-LINE: fcmeq v0.4s, v0.4s, #0.0
return AdvSimd.CompareEqual(Vector128<float>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<double> AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero_Swapped(Vector128<double> right)
{
// ARM64-FULL-LINE: fcmeq v0.2d, v0.2d, #0.0
return AdvSimd.Arm64.CompareEqual(Vector128<double>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<ulong> AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero_Swapped(Vector128<ulong> right)
{
// ARM64-FULL-LINE: cmeq v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareEqual(Vector128<ulong>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<long> AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero_Swapped(Vector128<long> right)
{
// ARM64-FULL-LINE: cmeq v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareEqual(Vector128<long>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero_Swapped(Vector64<float> right)
{
// ARM64-FULL-LINE: fcmeq s0, s0, #0.0
return AdvSimd.Arm64.CompareEqualScalar(Vector64<float>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<double> AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero_Swapped(Vector64<double> right)
{
// ARM64-FULL-LINE: fcmeq d0, d0, #0.0
return AdvSimd.Arm64.CompareEqualScalar(Vector64<double>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<ulong> AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero_Swapped(Vector64<ulong> right)
{
// ARM64-FULL-LINE: cmeq d0, d0, #0
return AdvSimd.Arm64.CompareEqualScalar(Vector64<ulong>.Zero, right);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<long> AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero_Swapped(Vector64<long> right)
{
// ARM64-FULL-LINE: cmeq d0, d0, #0
return AdvSimd.Arm64.CompareEqualScalar(Vector64<long>.Zero, right);
}
......@@ -364,48 +432,58 @@ static Vector64<long> AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero_Swapp
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<byte> AdvSimd_CompareGreaterThan_Vector64_Byte_Zero(Vector64<byte> left)
{
// ARM64-FULL-LINE: movi {{v[0-9]+}}.2s, #0
// ARM64-FULL-LINE-NEXT: cmhi {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
return AdvSimd.CompareGreaterThan(left, Vector64<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareGreaterThan_Vector64_Single_Zero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmgt v0.2s, v0.2s, #0.0
return AdvSimd.CompareGreaterThan(left, Vector64<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<byte> AdvSimd_CompareGreaterThan_Vector128_Byte_Zero(Vector128<byte> left)
{
// ARM64-FULL-LINE: movi {{v[0-9]+}}.4s, #0
// ARM64-FULL-LINE-NEXT: cmhi {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
return AdvSimd.CompareGreaterThan(left, Vector128<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareGreaterThan_Vector128_Single_Zero(Vector128<float> left)
{
// ARM64-FULL-LINE: fcmgt v0.4s, v0.4s, #0.0
return AdvSimd.CompareGreaterThan(left, Vector128<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<double> AdvSimd_Arm64_CompareGreaterThan_Vector128_Double_Zero(Vector128<double> left)
{
// ARM64-FULL-LINE: fcmgt v0.2d, v0.2d, #0.0
return AdvSimd.Arm64.CompareGreaterThan(left, Vector128<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<long> AdvSimd_Arm64_CompareGreaterThan_Vector128_Int64_Zero(Vector128<long> left)
{
// ARM64-FULL-LINE: cmgt v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareGreaterThan(left, Vector128<long>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<double> AdvSimd_Arm64_CompareGreaterThanScalar_Vector64_Double_Zero(Vector64<double> left)
{
// ARM64-FULL-LINE: fcmgt d0, d0, #0.0
return AdvSimd.Arm64.CompareGreaterThanScalar(left, Vector64<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<long> AdvSimd_Arm64_CompareGreaterThanScalar_Vector64_Int64_Zero(Vector64<long> left)
{
// ARM64-FULL-LINE: cmgt d0, d0, #0
return AdvSimd.Arm64.CompareGreaterThanScalar(left, Vector64<long>.Zero);
}
......@@ -414,48 +492,58 @@ static Vector64<long> AdvSimd_Arm64_CompareGreaterThanScalar_Vector64_Int64_Zero
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<byte> AdvSimd_CompareGreaterThanOrEqual_Vector64_Byte_Zero(Vector64<byte> left)
{
// ARM64-FULL-LINE: movi {{v[0-9]+}}.2s, #0
// ARM64-FULL-LINE-NEXT: cmhs {{v[0-9]+}}.8b, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b
return AdvSimd.CompareGreaterThanOrEqual(left, Vector64<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<float> AdvSimd_CompareGreaterThanOrEqual_Vector64_Single_Zero(Vector64<float> left)
{
// ARM64-FULL-LINE: fcmge v0.2s, v0.2s, #0.0
return AdvSimd.CompareGreaterThanOrEqual(left, Vector64<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<byte> AdvSimd_CompareGreaterThanOrEqual_Vector128_Byte_Zero(Vector128<byte> left)
{
// ARM64-FULL-LINE: movi {{v[0-9]+}}.4s, #0
// ARM64-FULL-LINE-NEXT: cmhs {{v[0-9]+}}.16b, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b
return AdvSimd.CompareGreaterThanOrEqual(left, Vector128<byte>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> AdvSimd_CompareGreaterThanOrEqual_Vector128_Single_Zero(Vector128<float> left)
{
// ARM64-FULL-LINE: fcmge v0.4s, v0.4s, #0.0
return AdvSimd.CompareGreaterThanOrEqual(left, Vector128<float>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<double> AdvSimd_Arm64_CompareGreaterThanOrEqual_Vector128_Double_Zero(Vector128<double> left)
{
// ARM64-FULL-LINE: fcmge v0.2d, v0.2d, #0.0
return AdvSimd.Arm64.CompareGreaterThanOrEqual(left, Vector128<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<long> AdvSimd_Arm64_CompareGreaterThanOrEqual_Vector128_Int64_Zero(Vector128<long> left)
{
// ARM64-FULL-LINE: cmge v0.2d, v0.2d, #0
return AdvSimd.Arm64.CompareGreaterThanOrEqual(left, Vector128<long>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<double> AdvSimd_Arm64_CompareGreaterThanOrEqualScalar_Vector64_Double_Zero(Vector64<double> left)
{
// ARM64-FULL-LINE: fcmge d0, d0, #0.0
return AdvSimd.Arm64.CompareGreaterThanOrEqualScalar(left, Vector64<double>.Zero);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector64<long> AdvSimd_Arm64_CompareGreaterThanOrEqualScalar_Vector64_Int64_Zero(Vector64<long> left)
{
// ARM64-FULL-LINE: cmge d0, d0, #0
return AdvSimd.Arm64.CompareGreaterThanOrEqualScalar(left, Vector64<long>.Zero);
}
......
......@@ -6,8 +6,20 @@
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CLRTestBatchPreCommands><![CDATA[
$(CLRTestBatchPreCommands)
set COMPlus_TieredCompilation=0
set COMPlus_JITMinOpts=0
]]></CLRTestBatchPreCommands>
<BashCLRTestPreCommands><![CDATA[
$(BashCLRTestPreCommands)
export COMPlus_TieredCompilation=0
export COMPlus_JITMinOpts=0
]]></BashCLRTestPreCommands>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
<Compile Include="$(MSBuildProjectName).cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
</ItemGroup>
</Project>
......@@ -9,12 +9,35 @@ class Program
[MethodImpl(MethodImplOptions.NoInlining)]
static uint PerformMod_1(uint i)
{
// X64-FULL-LINE: mov [[REG0:[a-z]+]], [[REG1:[a-z0-9]+]]
// X64-FULL-LINE-NEXT: and [[REG0]], 7
// ARM64-FULL-LINE: and w0, w0, #7
return i % 8;
}
[MethodImpl(MethodImplOptions.NoInlining)]
static int PerformMod_2(int i)
{
// X64-FULL-LINE: mov [[REG0:[a-z]+]], [[REG1:[a-z]+]]
// X64-FULL-LINE-NEXT: sar [[REG0]], 31
// X64-FULL-LINE-NEXT: and [[REG0]], 15
// X64-FULL-LINE-NEXT: add [[REG0]], [[REG1]]
// X64-FULL-LINE-NEXT: and [[REG0]], -16
// X64-WINDOWS-FULL-LINE-NEXT: mov [[REG2:[a-z]+]], [[REG1]]
// X64-WINDOWS-FULL-LINE-NEXT: sub [[REG2]], [[REG0]]
// X64-WINDOWS-FULL-LINE-NEXT: mov [[REG0]], [[REG2]]
// X64-LINUX-FULL-LINE-NEXT: sub [[REG1]], [[REG0]]
// X64-LINUX-FULL-LINE-NEXT: mov [[REG0]], [[REG1]]
// X64-OSX-FULL-LINE-NEXT: sub [[REG1]], [[REG0]]
// X64-OSX-FULL-LINE-NEXT: mov [[REG0]], [[REG1]]
// ARM64-FULL-LINE: and w1, w0, #15
// ARM64-FULL-LINE-NEXT: negs w0, w0
// ARM64-FULL-LINE-NEXT: and w0, w0, #15
// ARM64-FULL-LINE-NEXT: csneg w0, w1, w0, mi
return i % 16;
}
......@@ -27,6 +50,12 @@ static int PerformMod_3(int i, int j)
[MethodImpl(MethodImplOptions.NoInlining)]
static int MSUB(int a, int b, int c)
{
// X64-FULL-LINE: imul [[REG0:[a-z]+]], [[REG1:[a-z0-9]+]]
// X64-FULL-LINE-NEXT: mov [[REG2:[a-z]+]], [[REG3:[a-z]+]]
// X64-FULL-LINE-NEXT: sub [[REG2]], [[REG0]]
// ARM64-FULL-LINE: msub w0, w1, w2, w0
return a - b * c;
}
......
......@@ -6,9 +6,21 @@
<DebugType />
<Optimize>True</Optimize>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CLRTestBatchPreCommands><![CDATA[
$(CLRTestBatchPreCommands)
set COMPlus_TieredCompilation=0
set COMPlus_JITMinOpts=0
]]></CLRTestBatchPreCommands>
<BashCLRTestPreCommands><![CDATA[
$(BashCLRTestPreCommands)
export COMPlus_TieredCompilation=0
export COMPlus_JITMinOpts=0
]]></BashCLRTestPreCommands>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
<Compile Include="$(MSBuildProjectName).cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.CompilerServices;
public class Program
{
public static int Main()
{
Console.WriteLine(CallFoo(new C()));
return 100;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static int CallFoo<T>(T val) where T : IFace
{
// This is testing that a constrained.callvirt through a T variable doesn't use a helper lookup.
// CHECK-NOT: CORINFO_HELP
return val.Foo();
}
}
public interface IFace
{
int Foo();
}
public class C : IFace
{
public int Foo() => 0;
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册