From 2e497f1dcc6c352ca26eccf54fa63db58b5a354c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 21 Dec 2020 17:09:13 -0800 Subject: [PATCH 001/149] Initial commit --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..88da011 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Kunal Pathak + +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. From 778ed08e6b12d3e7dae406f48e4e157960d96dff Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 21 Dec 2020 17:10:40 -0800 Subject: [PATCH 002/149] Added operators and prototype code --- .gitignore | 3 + Antigen.csproj | 16 ++++ Antigen.sln | 30 ++++++ AstUtils.cs | 37 ++++++++ CSharpCompiler.cs | 117 ++++++++++++++++++++++++ ConfigOptions.cs | 85 +++++++++++++++++ Operators.cs | 87 ++++++++++++++++++ PRNG.cs | 226 ++++++++++++++++++++++++++++++++++++++++++++++ Program.cs | 24 +++++ README.md | 3 + RoslynTypes.cs | 20 ++++ RunOptions.cs | 12 +++ TestCase.cs | 202 +++++++++++++++++++++++++++++++++++++++++ 13 files changed, 862 insertions(+) create mode 100644 .gitignore create mode 100644 Antigen.csproj create mode 100644 Antigen.sln create mode 100644 AstUtils.cs create mode 100644 CSharpCompiler.cs create mode 100644 ConfigOptions.cs create mode 100644 Operators.cs create mode 100644 PRNG.cs create mode 100644 Program.cs create mode 100644 README.md create mode 100644 RoslynTypes.cs create mode 100644 RunOptions.cs create mode 100644 TestCase.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f677870 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin +obj +.vs \ No newline at end of file diff --git a/Antigen.csproj b/Antigen.csproj new file mode 100644 index 0000000..c031b5f --- /dev/null +++ b/Antigen.csproj @@ -0,0 +1,16 @@ + + + + Exe + net5.0 + _2020 + ab71806a-3bd8-4fb1-b0e2-9450aec41a9f + + + + + + + + + diff --git a/Antigen.sln b/Antigen.sln new file mode 100644 index 0000000..9663912 --- /dev/null +++ b/Antigen.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30410.220 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antigen", "Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FA00618-BD61-41BA-9044-1A08C274AA24}" + ProjectSection(SolutionItems) = preProject + Operators.cs = Operators.cs + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C8A4C87B-214A-406B-9FC6-68267A4E1493} + EndGlobalSection +EndGlobal diff --git a/AstUtils.cs b/AstUtils.cs new file mode 100644 index 0000000..7f66f39 --- /dev/null +++ b/AstUtils.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public class AstUtils + { + private List> AllExpressions = new List>(); + private List> AllStatements = new List>(); + private List> AllStatementsWithCFStmts = new List>(); + private List> AllTerminalExpressions = new List>(); + private List> AllTerminalStatements = new List>(); + private List> AllTerminalStatementsWithCFStmts = new List>(); + private List> AllOperators = new List>(); + + private ConfigOptions Options; + private RunOptions RunOptions; + private TestCase TestCase; + private static char[] Alphabet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + + public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) + { + Options = configOptions; + RunOptions = runOptions; + TestCase = tc; + + // Initialize operators + foreach (Operator op in Operator.GetOperators()) + { + AllOperators.Add(new Weights(op, Options.LookupOperator(op.Name))); + } + } + } +} diff --git a/CSharpCompiler.cs b/CSharpCompiler.cs new file mode 100644 index 0000000..2bcb9e8 --- /dev/null +++ b/CSharpCompiler.cs @@ -0,0 +1,117 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Emit; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Exprgen +{ + internal static class CSharpCompiler + { + + private static readonly MetadataReference[] s_references = + { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location), + MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), + // These two are needed to properly pick up System.Object when using methods on System.Console. + // See here: https://github.com/dotnet/corefx/issues/11601 + MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location), + MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Linq")).Location), + MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("mscorlib")).Location), + }; + + private static readonly CSharpCompilationOptions DebugOptions = + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Debug); + + private static readonly CSharpCompilationOptions ReleaseOptions = + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release); + + internal static void CompileAndExecute(string fileName) + { + string contents = File.ReadAllText(fileName); + CompilationUnitSyntax comp = SyntaxFactory.ParseCompilationUnit(contents, options: new CSharpParseOptions(LanguageVersion.Latest)); + //Console.WriteLine(comp.NormalizeWhitespace().ToFullString()); + + CompileResult compResult = Compile(comp); + if (compResult.Assembly == null) + { + Console.WriteLine("Got compiler errors:"); + Console.WriteLine(string.Join(Environment.NewLine, compResult.CompileErrors)); + } + else + { + Assembly asm = Assembly.Load(compResult.Assembly); + MethodInfo mainMethodInfo = asm.GetType("RyuJITTest").GetMethod("Main"); + Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); + + Exception ex = null; + //TextWriter origOut = Console.Out; + + MemoryStream ms = new MemoryStream(); + //StreamWriter sw = new StreamWriter(Console.s, Encoding.UTF8); + + try + { + //Console.SetOut(sw); + entryPoint(null); + } + catch (Exception caughtEx) + { + ex = caughtEx; + } + finally + { + //Console.SetOut(origOut); + //sw.Close(); + } + } + } + + private static CompileResult Compile(CompilationUnitSyntax program) + { + SyntaxTree[] trees = { SyntaxFactory.SyntaxTree(program, new CSharpParseOptions(LanguageVersion.Latest)) }; + CSharpCompilation comp = CSharpCompilation.Create("RyuJITTest", trees, s_references, ReleaseOptions); + + using (var ms = new MemoryStream()) + { + EmitResult result; + try + { + result = comp.Emit(ms); + } + catch (Exception ex) + { + return new CompileResult(ex, ImmutableArray.Empty, null); + } + + if (!result.Success) + return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null); + + return new CompileResult(null, ImmutableArray.Empty, ms.ToArray()); + } + } + } + + internal class CompileResult + { + public CompileResult(Exception roslynException, ImmutableArray compileErrors, byte[] assembly) + { + RoslynException = roslynException; + CompileErrors = compileErrors; + Assembly = assembly; + } + + public Exception RoslynException { get; } + public ImmutableArray CompileErrors { get; } + public byte[] Assembly { get; } + } + +} diff --git a/ConfigOptions.cs b/ConfigOptions.cs new file mode 100644 index 0000000..31f8606 --- /dev/null +++ b/ConfigOptions.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Antigen +{ + public class OptionsBase + { + } + + public class ConfigOptions : OptionsBase + { + public const string WeightSuffix = "Weight"; + + // Operator weights + public double UnaryPlusWeight = 1; + public double UnaryMinusWeight = 1; + public double PreIncrementWeight = 1; + public double PreDecrementWeight = 1; + public double PostIncrementWeight = 1; + public double PostDecrementWeight = 1; + public double LogicalNotWeight = 1; + public double BitwiseNotWeight = 1; + public double TypeOfWeight = 1; + + public double AddWeight = 1; + public double SubtractWeight = 1; + public double MultiplyWeight = 1; + public double DivideWeight = 1; + public double ModuloWeight = 1; + public double LeftShiftWeight = 1; + public double RightShiftWeight = 1; + + public double SimpleAssignmentWeight = 1; + public double AddAssignmentWeight = 1; + public double SubtractAssignmentWeight = 1; + public double MultiplyAssignmentWeight = 1; + public double DivideAssignmentWeight = 1; + public double ModuloAssignmentWeight = 1; + public double LeftShiftAssignmentWeight = 1; + public double RightShiftAssignmentWeight = 1; + + public double LogicalAndWeight = 1; + public double LogicalOrWeight = 1; + + public double BitwiseAndWeight = 1; + public double BitwiseOrWeight = 1; + public double ExclusiveOrWeight = 1; + + public double AndAssignmentWeight = 1; + public double OrAssignmentWeight = 1; + public double ExclusiveOrAssignmentWeight = 1; + + public double LessThanWeight = 1; + public double LessThanOrEqualWeight = 1; + public double GreaterThanWeight = 1; + public double GreaterThanOrEqualWeight = 1; + public double EqualsWeight = 1; + public double NotEqualsWeight = 1; + + public double LookupOperator(string str) + { + str = str.Replace("Expression", ""); + return Lookup(str + WeightSuffix); + } + + private double Lookup(string str) + { + FieldInfo target = typeof(ConfigOptions).GetField(str, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + + if (target == null) + { + Console.WriteLine("ERROR: didn't find weight for {0}; using 0 instead", str); + return 0; + } + + return (double)target.GetValue(this); + } + } +} diff --git a/Operators.cs b/Operators.cs new file mode 100644 index 0000000..1c54d6d --- /dev/null +++ b/Operators.cs @@ -0,0 +1,87 @@ +using Microsoft.CodeAnalysis.CSharp; +using System.Collections.Generic; + +namespace Antigen +{ + public struct Operator + { + public enum OpFlags + { + Comparison = 0x1, + Binary = 0x2, + Unary = 0x4, + Divide = 0x8, + Shift = 0x10, + IncrementDecrement = 0x20, + Math = 0x40, + Assignment = 0x80, + Logical = 0x100, + Bitwise = 0x200, + String = 0x400, + Yield = 0x800 + } + + public string Name => Oper.ToString(); + + public OpFlags Flags; + public SyntaxKind Oper; + private static readonly List operators = new List() + { + new Operator(SyntaxKind.UnaryPlusExpression, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.UnaryMinusExpression, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.PreIncrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PreDecrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostIncrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostDecrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.LogicalNotExpression, OpFlags.Unary), + new Operator(SyntaxKind.BitwiseNotExpression, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.TypeOfExpression, OpFlags.Unary), + + new Operator(SyntaxKind.AddExpression, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.SubtractExpression, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.MultiplyExpression, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.DivideExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), + new Operator(SyntaxKind.ModuloExpression, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.LeftShiftExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), + new Operator(SyntaxKind.RightShiftExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), + + new Operator(SyntaxKind.SimpleAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.AddAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), + new Operator(SyntaxKind.SubtractAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.MultiplyAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.DivideAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), + new Operator(SyntaxKind.ModuloAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.LeftShiftAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + new Operator(SyntaxKind.RightShiftAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + + new Operator(SyntaxKind.LogicalAndExpression, OpFlags.Binary | OpFlags.Logical), + new Operator(SyntaxKind.LogicalOrExpression, OpFlags.Binary | OpFlags.Logical), + + new Operator(SyntaxKind.BitwiseAndExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.BitwiseOrExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.ExclusiveOrExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + + new Operator(SyntaxKind.AndAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.OrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + + new Operator(SyntaxKind.LessThanExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.LessThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.GreaterThanExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.GreaterThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.EqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.NotEqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) + }; + + public Operator(SyntaxKind oper, OpFlags flags ) + { + Oper = oper; + Flags = flags; + } + + public static List GetOperators() + { + return operators; + } + } +} \ No newline at end of file diff --git a/PRNG.cs b/PRNG.cs new file mode 100644 index 0000000..99096a7 --- /dev/null +++ b/PRNG.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; + +namespace Antigen +{ + public class Weights + { + public double Weight; + public T Data; + + public Weights(T data_, double Weight_) + { + Data = data_; + Weight = Weight_; + } + }; + + public class PRNG + { + private static System.Security.Cryptography.RNGCryptoServiceProvider SecureRand; + private static Dictionary PerThreadRand = new Dictionary(); + private static Dictionary PerThreadSeed = new Dictionary(); + private static bool isFixSeed = false; + + static public void Initialize(int seed) + { + if (seed == -1) + { + isFixSeed = false; + SecureRand = new System.Security.Cryptography.RNGCryptoServiceProvider(); + } + else + { + isFixSeed = true; + lock (PerThreadRand) + { + int currentThreadId = Thread.CurrentThread.ManagedThreadId; + int currentSeed = seed + (/*Program.RunOptions.NumThreads*/ 5 * PerThreadRand.Count); // every thread gets seed value in multiples of 100s + if (!PerThreadRand.ContainsKey(currentThreadId)) + { + PerThreadRand[currentThreadId] = new Random(currentSeed); + PerThreadSeed[currentThreadId] = currentSeed; + } + } + } + } + + static public int GetSeed() + { + int seedValue = -1; + if (isFixSeed) + { + int currentThreadId = Thread.CurrentThread.ManagedThreadId; + + if (PerThreadSeed.ContainsKey(currentThreadId)) + { + seedValue = PerThreadSeed[currentThreadId]; + } + } + return seedValue; + } + + static public int Next(int max) + { + return Next(0, max); + } + + static public int Next(int min, int max) + { + int ret; + + if (min > max) + { + int temp = max; + max = min; + min = temp; + } + + if (isFixSeed) + { + ret = PerThreadRand[Thread.CurrentThread.ManagedThreadId].Next(min, max); + } + else + { + //if sample set is 0 then just return 0 + if (max == 0) + { + ret = 0; + } + else + { + Debug.Assert(min != max, "min = max in PRNG.Next()"); + + Byte[] data = new Byte[4]; + SecureRand.GetBytes(data); + + // We don't want the high bit set, since it has to be a positive number. + data[3] = (byte)((int)data[3] & 0x7F); + + ret = (data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)) % max; + // If value is less than adjust it to be higer than min + if (ret < min) + { + ret = min + (ret % (max - min)); + } + } + } + + return ret; + } + + static public long NextLong(long max) + { + long ret = 0; + + if (isFixSeed) + { + //if sample set is 0 then just return 0 + if (max == 0) + { + ret = 0; + } + else + { + int shift = 0; + for (int i = 0; i < 4; ++i) + { + long data = (long)PerThreadRand[Thread.CurrentThread.ManagedThreadId].Next(65536); + ret += data << shift; + shift += 16; + } + ret %= max; + } + } + else + { + //if sample set is 0 then just return 0 + if (max == 0) + { + ret = 0; + } + else + { + Byte[] origData = new Byte[8]; + SecureRand.GetBytes(origData); + + long[] data = new long[8]; + for (int i = 0; i < 8; ++i) + data[i] = (long)origData[i]; + + ret = (long)(data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) + + (data[4] << 32) + (data[5] << 40) + (data[6] << 48) + (data[7] << 56)) % max; + } + } + + return ret; + } + + /// + /// Returns number between 0 and max (inclusive) based on exponential function i.e. + /// lowest value (1) gets higest weightage followed by 2, ..., max. + /// + /// + /// + public static int NextWithExponentialFactor(int max, double exponentialFactor, int min = 0) + { + if (max == 0) + return 0; + + Debug.Assert(min < max, "min < max inside PRNG.NextExponential()"); + List> choices = new List>(); + int N = min; + while (max >= min) + { + double weight = Math.Pow(max, exponentialFactor); + // if the weight is too high because max/exponentialFactor was very huge number, then there is less chance that lower + // numbers will be selected, so just return one of the first 3 values. + if(double.IsNaN(weight) || double.IsInfinity(weight) || double.IsPositiveInfinity(weight) || double.IsNegativeInfinity(weight)) + { + return PRNG.Next(min, min + 3); + } + choices.Add(new Weights(N++, weight)); + max--; + } + return WeightedChoice(choices); + } + + /// + /// Decide - takes a %weight which is between 0-1. + /// + /// % + /// + public static bool Decide(double weight) + { + Debug.Assert(weight >= 0 && weight <= 1); + return PRNG.Next(Int32.MaxValue) <= weight * Int32.MaxValue; + } + + public static T WeightedChoice(IEnumerable> choices) + { + // Sum up all of the weights + double sum = (from z in choices + select z.Weight).Sum(); + + // Create a normalized random value + double rand = Next(65536) * sum / 65536.0; + + double prev = 0; + double currMax = 0; + foreach(Weights curr in choices) + { + prev = currMax; + currMax += curr.Weight; + if (rand >= prev && rand < currMax) + { + return curr.Data; + } + } + System.Diagnostics.Debug.Assert(false, "Should never get here!"); + return default(T); + } + }; +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..54076d8 --- /dev/null +++ b/Program.cs @@ -0,0 +1,24 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editing; +using System; + +namespace Antigen +{ + class Program + { + static void Main(string[] args) + { + + + + //GenerateTestCase(); + int testId = 1; + while (true) + { + TestCase testCase = new TestCase(testId++); + testCase.Generate(); + testCase.CompileAndExecute(); + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..7277cdb --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +Antigen + +C# test generator and RyuJIT tester \ No newline at end of file diff --git a/RoslynTypes.cs b/RoslynTypes.cs new file mode 100644 index 0000000..4fde9e7 --- /dev/null +++ b/RoslynTypes.cs @@ -0,0 +1,20 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.VisualBasic.CompilerServices; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public class Rsln + { + internal static SyntaxGenerator synGen = SyntaxGenerator.GetGenerator(new AdhocWorkspace(), LanguageNames.CSharp); + internal static readonly CSharpCompilationOptions DebugOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Debug); + internal static readonly CSharpCompilationOptions ReleaseOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release); + + } +} diff --git a/RunOptions.cs b/RunOptions.cs new file mode 100644 index 0000000..7bde936 --- /dev/null +++ b/RunOptions.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public class RunOptions + { + } +} diff --git a/TestCase.cs b/TestCase.cs new file mode 100644 index 0000000..30a1b5b --- /dev/null +++ b/TestCase.cs @@ -0,0 +1,202 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Emit; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public class TestCase + { + #region Compiler options + + public enum CompilationType + { + Debug, Release + }; + + #endregion + + #region PreComputed roslyn syntax tress + #endregion + + + private SyntaxGenerator synGen = Rsln.synGen; + private SyntaxNode testClass; + + private List classesList; + private List methodsList; + private List propertiesList; + private List fieldsList; + + + public string Name { get; private set; } + + public TestCase(int testId) + { + synGen = SyntaxGenerator.GetGenerator(new AdhocWorkspace(), LanguageNames.CSharp); + Name = string.Format("Test{0:0000}", testId); + + //var x = SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.IdentifierName("a"), SyntaxFactory.IdentifierName("b")); + var x = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.UnaryPlusExpression, SyntaxFactory.ParseExpression("a")); + //(SyntaxKind.AddExpression, SyntaxFactory.IdentifierName("a"), SyntaxFactory.IdentifierName("b")); + Console.WriteLine(x.ToFullString()); + var ifs = SyntaxFactory.IfStatement(SyntaxFactory.IdentifierName("a"), SyntaxFactory.ParseStatement("1")); + Console.WriteLine(ifs.ToFullString()); + SyntaxList stmts; + for (int i = 0; i < 10; i++) + { + stmts = stmts.Add(SyntaxFactory.ParseStatement("x = " + i)); + } + //SyntaxFactory.expre + var block = SyntaxFactory.Block(stmts); + ifs = ifs.WithStatement(block); + Console.WriteLine(ifs.ToFullString()); + //var y = x.WithLeft(SyntaxFactory.IdentifierName("x")).WithRight(SyntaxFactory.IdentifierName("y")); + //Console.WriteLine(y.ToFullString()); + } + + public void Generate() + { + var usingDirectives = synGen.NamespaceImportDeclaration("System"); + + List methods = new List(); + for (int i = 0; i < 5; i++) + { + methods.Add(synGen.MethodDeclaration("Method" + i)); + } + + //synGen.AddExpression() + + // TODO: Figure out why we cannot have string[] in parameter. The Emit() function fails in its presence. + var mainArgs = new SyntaxNode[] { + synGen.ParameterDeclaration("args", /*synGen.ArrayTypeExpression(synGen.TypeExpression(SpecialType.System_String))*/synGen.TypeExpression(SpecialType.System_String)) }; + + methods.Add(synGen.MethodDeclaration("Main", parameters: mainArgs, accessibility: Accessibility.Public, modifiers: DeclarationModifiers.Static )); + + var classDefinition = synGen.ClassDeclaration(Name, null, Accessibility.Public, members: methods); + + var namespaceDeclaration = synGen.NamespaceDeclaration("MyTypes", classDefinition); + + + testClass = synGen.CompilationUnit(usingDirectives, namespaceDeclaration).NormalizeWhitespace(); + } + + public void CompileAndExecute() + { + CompileResult compileResult = Compile(CompilationType.Release); + Execute(compileResult); + } + + private CompileResult Compile(CompilationType compilationType) + { + Console.WriteLine(testClass.ToFullString()); + + MetadataReference mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); + MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location); + MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location); + + MetadataReference[] references = { mscorlib, codeAnalysis, csharpCodeAnalysis }; + + var cc = CSharpCompilation.Create("test000", new SyntaxTree[] { testClass.SyntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); + + using (var ms = new MemoryStream()) + { + EmitResult result; + try + { + result = cc.Emit(ms); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return new CompileResult(ex, ImmutableArray.Empty, null); + } + + if (!result.Success) + return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null); + + return new CompileResult(null, ImmutableArray.Empty, ms.ToArray()); + } + } + + private void Execute(CompileResult compileResult) + { + if (compileResult.Assembly == null) + { + Console.WriteLine("Got compiler errors:"); + Console.WriteLine(string.Join(Environment.NewLine, compileResult.CompileErrors)); + } + else + { + Assembly asm = Assembly.Load(compileResult.Assembly); + MethodInfo mainMethodInfo = asm.GetType("MyTypes.Test000").GetMethod("Main"); + Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); + + Exception ex = null; + //TextWriter origOut = Console.Out; + + MemoryStream ms = new MemoryStream(); + //StreamWriter sw = new StreamWriter(Console.s, Encoding.UTF8); + + try + { + //Console.SetOut(sw); + entryPoint(null); + } + catch (Exception caughtEx) + { + ex = caughtEx; + } + finally + { + //Console.SetOut(origOut); + //sw.Close(); + } + } + } + } + + internal class CompileResult + { + public CompileResult(Exception roslynException, ImmutableArray compileErrors, byte[] assembly) + { + RoslynException = roslynException; + CompileErrors = compileErrors; + Assembly = assembly; + } + + public Exception RoslynException { get; } + public ImmutableArray CompileErrors { get; } + public byte[] Assembly { get; } + } + + public class TestClass + { + + } + + public class TestMainClass : TestClass + { + + } + + public class TestMethod + { + + } + + public class TestMainMethod : TestMethod + { + + } +} From bcb2e00e386f8d6951c7543f79c853ff060ed3e1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 23 Dec 2020 02:18:14 -0800 Subject: [PATCH 003/149] int x = 1 --- Antigen.csproj | 2 +- AstUtils.cs | 37 ------ BaseMethod.cs | 82 ++++++++++++ ConfigOptions.cs | 55 ++++++-- Helpers/Literals.cs | 177 +++++++++++++++++++++++++ Helpers/VariableDeclarationHelper.cs | 35 +++++ Program.cs | 9 +- README.md | 4 +- TestCase.cs | 112 +++++++--------- Tree/AstUtils.cs | 190 +++++++++++++++++++++++++++ Tree/Expressions.cs | 12 ++ Operators.cs => Tree/Operators.cs | 23 ++-- Tree/Scope.cs | 23 ++++ Tree/Statements.cs | 11 ++ Tree/Types.cs | 81 ++++++++++++ 15 files changed, 727 insertions(+), 126 deletions(-) delete mode 100644 AstUtils.cs create mode 100644 BaseMethod.cs create mode 100644 Helpers/Literals.cs create mode 100644 Helpers/VariableDeclarationHelper.cs create mode 100644 Tree/AstUtils.cs create mode 100644 Tree/Expressions.cs rename Operators.cs => Tree/Operators.cs (91%) create mode 100644 Tree/Scope.cs create mode 100644 Tree/Statements.cs create mode 100644 Tree/Types.cs diff --git a/Antigen.csproj b/Antigen.csproj index c031b5f..c47db71 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -3,7 +3,7 @@ Exe net5.0 - _2020 + Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/AstUtils.cs b/AstUtils.cs deleted file mode 100644 index 7f66f39..0000000 --- a/AstUtils.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Antigen -{ - public class AstUtils - { - private List> AllExpressions = new List>(); - private List> AllStatements = new List>(); - private List> AllStatementsWithCFStmts = new List>(); - private List> AllTerminalExpressions = new List>(); - private List> AllTerminalStatements = new List>(); - private List> AllTerminalStatementsWithCFStmts = new List>(); - private List> AllOperators = new List>(); - - private ConfigOptions Options; - private RunOptions RunOptions; - private TestCase TestCase; - private static char[] Alphabet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - - public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) - { - Options = configOptions; - RunOptions = runOptions; - TestCase = tc; - - // Initialize operators - foreach (Operator op in Operator.GetOperators()) - { - AllOperators.Add(new Weights(op, Options.LookupOperator(op.Name))); - } - } - } -} diff --git a/BaseMethod.cs b/BaseMethod.cs new file mode 100644 index 0000000..b7a6c35 --- /dev/null +++ b/BaseMethod.cs @@ -0,0 +1,82 @@ +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen +{ + public class BaseMethod + { + private TestCase testCase; + private string Name; + private List variableNames = new List(); + + public MethodDeclarationSyntax GeneratedMethod { get; private set;} + + public AstUtils GetASTUtils() + { + return testCase.AstUtils; + } + + public BaseMethod(TestCase tc, string name) + { + testCase = tc; + Name = name; + } + + public void Generate() + { + MethodDeclarationSyntax methodDeclaration = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Name).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + IList methodBody = new List(); + for (int i = 0; i < 10; i++) + { + StmtKind cur = GetASTUtils().GetRandomStatemet(); + methodBody.Add(StatementHelper(cur)); + } + + // print all variables + foreach(string variableName in variableNames) + { + methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + } + + GeneratedMethod = methodDeclaration.WithBody(Block(methodBody)); + } + + public StatementSyntax StatementHelper(StmtKind stmtKind) + { + switch (stmtKind) + { + case StmtKind.VariableDeclaration: + ExprType variableType = GetASTUtils().GetRandomType(); + string variableName = Helpers.GetVariableName(variableType, variableNames.Count); + variableNames.Add(variableName); + + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpression(), variableType); + return SyntaxFactory.LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); + + default: + Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); + break; + } + return null; + } + + public ExpressionSyntax ExprHelper(ExprKind exprKind, ExprType exprType) + { + switch (exprKind) + { + case ExprKind.LiteralExpression: + return Helpers.GetLiteralExpression(exprType); + + default: + Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); + break; + } + return null; + } + } +} diff --git a/ConfigOptions.cs b/ConfigOptions.cs index 31f8606..8140828 100644 --- a/ConfigOptions.cs +++ b/ConfigOptions.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; +using System; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Xml; namespace Antigen { @@ -17,6 +13,28 @@ public class ConfigOptions : OptionsBase { public const string WeightSuffix = "Weight"; + // Expression weights + public double LiteralWeight = 1; + + // Statement weights + public double VariableDeclarationWeight = 1; + + // Type weights + public double BooleanWeight = 1; + public double ByteWeight = 1; + public double CharWeight = 1; + public double DecimalWeight = 1; + public double DoubleWeight = 1; + public double Int16Weight = 1; + public double Int32Weight = 1; + public double Int64Weight = 1; + public double SByteWeight = 1; + public double SingleWeight = 1; + public double StringWeight = 1; + public double UInt16Weight = 1; + public double UInt32Weight = 1; + public double UInt64Weight = 1; + // Operator weights public double UnaryPlusWeight = 1; public double UnaryMinusWeight = 1; @@ -63,8 +81,29 @@ public class ConfigOptions : OptionsBase public double EqualsWeight = 1; public double NotEqualsWeight = 1; - public double LookupOperator(string str) + public double Lookup(ExprType type) + { + string str = Enum.GetName(typeof(Microsoft.CodeAnalysis.SpecialType), type.DataType); + str = str.Replace("System_", ""); + return Lookup(str + WeightSuffix); + } + + public double Lookup(Operator oper) + { + string str = Enum.GetName(typeof(SyntaxKind), oper.Oper); + str = str.Replace("Expression", ""); + return Lookup(str + WeightSuffix); + } + + public double Lookup(StmtKind stmt) + { + string str = Enum.GetName(typeof(StmtKind), stmt); + return Lookup(str + WeightSuffix); + } + + public double Lookup(ExprKind expr) { + string str = Enum.GetName(typeof(ExprKind), expr); str = str.Replace("Expression", ""); return Lookup(str + WeightSuffix); } diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs new file mode 100644 index 0000000..639ef24 --- /dev/null +++ b/Helpers/Literals.cs @@ -0,0 +1,177 @@ +using Antigen.Tree; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen +{ + public static partial class Helpers + { + private static char[] Alphabet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + + public static byte GetRandomByte() + { + return (byte)PRNG.Next(byte.MinValue, byte.MaxValue); + } + + public static short GetRandomShort() + { + return (short)PRNG.Next(short.MinValue, short.MaxValue); + } + + public static int GetRandomInt() + { + return PRNG.Next(int.MinValue, int.MaxValue); + } + + public static long GetRandomLong() + { + return PRNG.NextLong(long.MaxValue); + } + + public static ushort GetRandomUShort() + { + return (ushort)PRNG.Next(ushort.MaxValue); + } + + public static uint GetRandomUInt() + { + return (uint)PRNG.NextLong(uint.MaxValue); + } + + public static ulong GetRandomULong() + { + return (ulong)PRNG.NextLong(long.MaxValue); + } + + public static char GetRandomChar() + { + return Alphabet[PRNG.Next(Alphabet.Length)]; + } + + public static string GetRandomString(int length = -1) + { + length = (length == -1) ? PRNG.Next(10) : length; + StringBuilder strBuilder = new StringBuilder(); + for (int c = 0; c < length; c++) + { + strBuilder.Append(Alphabet[PRNG.Next(Alphabet.Length)]); + } + return strBuilder.ToString(); + } + + public static bool GetRandomBoolean() + { + return PRNG.Decide(0.5) ? true : false; + } + + public static sbyte GetRandomSByte() + { + return (sbyte)PRNG.Next(sbyte.MinValue, sbyte.MaxValue); + } + + public static float GetRandomFloat() + { + return (float)(PRNG.Next(int.MaxValue) + 1.5); + } + + public static double GetRandomDouble() + { + return (double)(PRNG.Next(int.MaxValue) + 2.5); + } + + public static decimal GetRandomDecimal() + { + return (decimal)(PRNG.Next(int.MaxValue) + 3.5); + } + + public static LiteralExpressionSyntax GetLiteralExpression(ExprType literalType) + { + SyntaxToken literalToken; + SyntaxKind kind; + switch (literalType.ValueType) + { + case Tree.ValueType.Boolean: + if (GetRandomBoolean()) + { + kind = SyntaxKind.TrueLiteralExpression; + literalToken = Token(SyntaxKind.TrueKeyword); + } + else + { + kind = SyntaxKind.FalseLiteralExpression; + literalToken = Token(SyntaxKind.FalseKeyword); + } + break; + case Tree.ValueType.Byte: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomByte()); + break; + case Tree.ValueType.Char: + kind = SyntaxKind.CharacterLiteralExpression; + literalToken = Literal(GetRandomChar()); + break; + case Tree.ValueType.Int16: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomShort()); + break; + case Tree.ValueType.Int32: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomInt()); + break; + case Tree.ValueType.Int64: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomLong()); + break; + case Tree.ValueType.UInt16: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomUShort()); + break; + case Tree.ValueType.UInt32: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomUInt()); + break; + case Tree.ValueType.UInt64: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomULong()); + break; + case Tree.ValueType.SByte: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomSByte()); + break; + case Tree.ValueType.Single: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomFloat()); + break; + case Tree.ValueType.Decimal: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomDecimal()); + break; + case Tree.ValueType.Double: + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(GetRandomDouble()); + break; + case Tree.ValueType.String: + kind = SyntaxKind.StringLiteralExpression; + literalToken = Literal(GetRandomString()); + break; + default: + Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.ValueType), literalType.ValueType))); + + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(1); + break; + + } + + return LiteralExpression(kind, literalToken); + } + } +} diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs new file mode 100644 index 0000000..eab04c4 --- /dev/null +++ b/Helpers/VariableDeclarationHelper.cs @@ -0,0 +1,35 @@ +using Antigen.Tree; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen +{ + public static partial class Helpers + { + public static VariableDeclarationSyntax GetVariableDeclaration(ExprType variableType, string variableName, ExpressionSyntax value) + { + return VariableDeclaration( + PredefinedType( + Token(variableType.TypeKind))) + .WithVariables( + SingletonSeparatedList( + VariableDeclarator( + Identifier(variableName)) + .WithInitializer( + EqualsValueClause(value)))); + } + + public static string GetVariableName(ExprType variableType, int id) + { + return Enum.GetName(typeof(SpecialType), variableType.DataType).Replace("System_", "").ToLower() + "_" + id; + } + } +} diff --git a/Program.cs b/Program.cs index 54076d8..ecd6478 100644 --- a/Program.cs +++ b/Program.cs @@ -1,15 +1,10 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editing; -using System; - -namespace Antigen +namespace Antigen { class Program { static void Main(string[] args) { - - + PRNG.Initialize(5); //GenerateTestCase(); int testId = 1; diff --git a/README.md b/README.md index 7277cdb..5583fe5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ Antigen -C# test generator and RyuJIT tester \ No newline at end of file +C# test generator and RyuJIT tester - Named after Covid-19 antigen test. + +1. Variable declaration where RHS is literal. \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 30a1b5b..78484af 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -1,7 +1,7 @@ -using Microsoft.CodeAnalysis; +using Antigen.Tree; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Emit; using System; using System.Collections.Generic; @@ -9,9 +9,7 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen { @@ -29,66 +27,46 @@ public enum CompilationType #region PreComputed roslyn syntax tress #endregion + private const string MainMethodName = "MainMethod"; - private SyntaxGenerator synGen = Rsln.synGen; private SyntaxNode testClass; private List classesList; private List methodsList; private List propertiesList; private List fieldsList; - public string Name { get; private set; } + public AstUtils AstUtils { get; private set; } public TestCase(int testId) { - synGen = SyntaxGenerator.GetGenerator(new AdhocWorkspace(), LanguageNames.CSharp); - Name = string.Format("Test{0:0000}", testId); - - //var x = SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.IdentifierName("a"), SyntaxFactory.IdentifierName("b")); - var x = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.UnaryPlusExpression, SyntaxFactory.ParseExpression("a")); - //(SyntaxKind.AddExpression, SyntaxFactory.IdentifierName("a"), SyntaxFactory.IdentifierName("b")); - Console.WriteLine(x.ToFullString()); - var ifs = SyntaxFactory.IfStatement(SyntaxFactory.IdentifierName("a"), SyntaxFactory.ParseStatement("1")); - Console.WriteLine(ifs.ToFullString()); - SyntaxList stmts; - for (int i = 0; i < 10; i++) - { - stmts = stmts.Add(SyntaxFactory.ParseStatement("x = " + i)); - } - //SyntaxFactory.expre - var block = SyntaxFactory.Block(stmts); - ifs = ifs.WithStatement(block); - Console.WriteLine(ifs.ToFullString()); - //var y = x.WithLeft(SyntaxFactory.IdentifierName("x")).WithRight(SyntaxFactory.IdentifierName("y")); - //Console.WriteLine(y.ToFullString()); + AstUtils = new AstUtils(this, new ConfigOptions(), null); + Name = "TestClass" + testId; } public void Generate() { - var usingDirectives = synGen.NamespaceImportDeclaration("System"); + BaseMethod mainMethod = new BaseMethod(this, MainMethodName); + mainMethod.Generate(); - List methods = new List(); - for (int i = 0; i < 5; i++) + IList methods = new List() { mainMethod }; + + for (int i = 1; i < 5; i++) { - methods.Add(synGen.MethodDeclaration("Method" + i)); + var testMethod = new BaseMethod(this, "Method" + i); + methods.Add(testMethod); + testMethod.Generate(); } - //synGen.AddExpression() - - // TODO: Figure out why we cannot have string[] in parameter. The Emit() function fails in its presence. - var mainArgs = new SyntaxNode[] { - synGen.ParameterDeclaration("args", /*synGen.ArrayTypeExpression(synGen.TypeExpression(SpecialType.System_String))*/synGen.TypeExpression(SpecialType.System_String)) }; - - methods.Add(synGen.MethodDeclaration("Main", parameters: mainArgs, accessibility: Accessibility.Public, modifiers: DeclarationModifiers.Static )); - - var classDefinition = synGen.ClassDeclaration(Name, null, Accessibility.Public, members: methods); - - var namespaceDeclaration = synGen.NamespaceDeclaration("MyTypes", classDefinition); - - - testClass = synGen.CompilationUnit(usingDirectives, namespaceDeclaration).NormalizeWhitespace(); + ClassDeclarationSyntax klass = ClassDeclaration(Name).WithMembers(new SyntaxList(methods.Select(m => m.GeneratedMethod))); + testClass = CompilationUnit() + .WithUsings( + SingletonList( + UsingDirective( + IdentifierName("System")))) + .WithMembers( + SingletonList(klass)).NormalizeWhitespace(); } public void CompileAndExecute() @@ -99,15 +77,19 @@ public void CompileAndExecute() private CompileResult Compile(CompilationType compilationType) { - Console.WriteLine(testClass.ToFullString()); + Console.WriteLine(testClass.ToString()); - MetadataReference mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); + string corelibPath = typeof(object).Assembly.Location; + string otherAssembliesPath = Path.GetDirectoryName(corelibPath); + MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); + MetadataReference systemConsole = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Console.dll")); + MetadataReference systemRuntime = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Runtime.dll")); MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location); MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location); - MetadataReference[] references = { mscorlib, codeAnalysis, csharpCodeAnalysis }; + MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - var cc = CSharpCompilation.Create("test000", new SyntaxTree[] { testClass.SyntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); + var cc = CSharpCompilation.Create(Name, new SyntaxTree[] { testClass.SyntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); using (var ms = new MemoryStream()) { @@ -129,6 +111,7 @@ private CompileResult Compile(CompilationType compilationType) } } + private delegate void MainMethodInvoke(); private void Execute(CompileResult compileResult) { if (compileResult.Assembly == null) @@ -139,8 +122,9 @@ private void Execute(CompileResult compileResult) else { Assembly asm = Assembly.Load(compileResult.Assembly); - MethodInfo mainMethodInfo = asm.GetType("MyTypes.Test000").GetMethod("Main"); - Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); + Type testClassType = asm.GetType(Name); + MethodInfo mainMethodInfo = testClassType.GetMethod(MainMethodName); + MainMethodInvoke entryPoint = (MainMethodInvoke)Delegate.CreateDelegate(typeof(MainMethodInvoke), Activator.CreateInstance(testClassType), mainMethodInfo); Exception ex = null; //TextWriter origOut = Console.Out; @@ -151,7 +135,7 @@ private void Execute(CompileResult compileResult) try { //Console.SetOut(sw); - entryPoint(null); + entryPoint(); } catch (Exception caughtEx) { @@ -180,23 +164,23 @@ public CompileResult(Exception roslynException, ImmutableArray compi public byte[] Assembly { get; } } - public class TestClass - { + //public class TestClass + //{ - } + //} - public class TestMainClass : TestClass - { + //public class TestMainClass : TestClass + //{ - } + //} - public class TestMethod - { + //public class TestMethod + //{ - } + //} - public class TestMainMethod : TestMethod - { + //public class TestMainMethod : TestMethod + //{ - } + //} } diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs new file mode 100644 index 0000000..18dce3b --- /dev/null +++ b/Tree/AstUtils.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Antigen.Tree +{ + public class AstUtils + { + private List> AllExpressions = new List>(); + private List> AllStatements = new List>(); + private List> AllTypes = new List>(); + private List> AllStatementsWithCFStmts = new List>(); + private List> AllTerminalExpressions = new List>(); + private List> AllTerminalStatements = new List>(); + private List> AllTerminalStatementsWithCFStmts = new List>(); + private List> AllOperators = new List>(); + + private ConfigOptions Options; + private RunOptions RunOptions; + private TestCase TestCase; + + public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) + { + Options = configOptions; + RunOptions = runOptions; + TestCase = tc; + + // Initialize types + foreach (ExprType type in ExprType.GetTypes()) + { + AllTypes.Add(new Weights(type, Options.Lookup(type))); + } + + // Initialize statements + foreach (StmtKind stmt in (StmtKind[])Enum.GetValues(typeof(StmtKind))) + { + AllStatements.Add(new Weights(stmt, Options.Lookup(stmt))); + } + + // Initialize expressions + foreach (ExprKind expr in (ExprKind[])Enum.GetValues(typeof(ExprKind))) + { + AllExpressions.Add(new Weights(expr, Options.Lookup(expr))); + } + + // Initialize operators + foreach (Operator oper in Operator.GetOperators()) + { + AllOperators.Add(new Weights(oper, Options.Lookup(oper))); + } + } + + #region Random type methods + public ExprType GetRandomType() + { + // Select all appropriate statements + IEnumerable> types = + from z in AllTypes + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(types); + } + #endregion + + #region Random statement methods + + public ExprKind GetRandomExpression() + { + // Select all appropriate statements + IEnumerable> exprs = + from z in AllExpressions + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(exprs); + } + + #endregion + + #region Random statement methods + + public StmtKind GetRandomStatemet() + { + // Select all appropriate statements + IEnumerable> stmts = + from z in AllStatements + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(stmts); + } + + #endregion + + #region Random operator methods + + public Operator GetRandomBinaryOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.Binary) && !z.Data.HasFlag(Operator.OpFlags.Assignment) + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + + public Operator GetRandomComparisonOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.Comparison) + where z.Weight != 0 + select z; + + // If we've disabled all comparison operators, just use another binary operator. + if (ops.Count() == 0) + { + return GetRandomBinaryOperator(); + } + else + { + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + } + + public Operator GetRandomLogicalOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.Logical) + where z.Weight != 0 + select z; + + // If we've disabled all comparison operators, just use another binary operator. + if (ops.Count() == 0) + { + return GetRandomBinaryOperator(); + } + else + { + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + } + + public Operator GetRandomUnaryOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.Unary) + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + + public Operator GetRandomAssignmentOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.Assignment) + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + + public Operator GetRandomStringOperator() + { + // Select all appropriate operators + IEnumerable> ops = + from z in AllOperators + where z.Data.HasFlag(Operator.OpFlags.String) + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + #endregion + + } +} diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs new file mode 100644 index 0000000..d234a35 --- /dev/null +++ b/Tree/Expressions.cs @@ -0,0 +1,12 @@ +namespace Antigen.Tree +{ + public enum ExprKind + { + LiteralExpression + } + + //public struct Expression + //{ + + //} +} diff --git a/Operators.cs b/Tree/Operators.cs similarity index 91% rename from Operators.cs rename to Tree/Operators.cs index 1c54d6d..6470beb 100644 --- a/Operators.cs +++ b/Tree/Operators.cs @@ -1,7 +1,7 @@ using Microsoft.CodeAnalysis.CSharp; using System.Collections.Generic; -namespace Antigen +namespace Antigen.Tree { public struct Operator { @@ -21,10 +21,17 @@ public enum OpFlags Yield = 0x800 } - public string Name => Oper.ToString(); + //public string Name => Oper.ToString(); public OpFlags Flags; public SyntaxKind Oper; + + public bool HasFlag(OpFlags flag) + { + bool val = (Flags & flag) != 0; + return val; + } + private static readonly List operators = new List() { new Operator(SyntaxKind.UnaryPlusExpression, OpFlags.Unary | OpFlags.Math), @@ -37,7 +44,7 @@ public enum OpFlags new Operator(SyntaxKind.BitwiseNotExpression, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), new Operator(SyntaxKind.TypeOfExpression, OpFlags.Unary), - new Operator(SyntaxKind.AddExpression, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.AddExpression, OpFlags.Binary | OpFlags.Math | OpFlags.String), new Operator(SyntaxKind.SubtractExpression, OpFlags.Binary | OpFlags.Math), new Operator(SyntaxKind.MultiplyExpression, OpFlags.Binary | OpFlags.Math), new Operator(SyntaxKind.DivideExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), @@ -65,15 +72,15 @@ public enum OpFlags new Operator(SyntaxKind.OrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.LessThanExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.LessThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.GreaterThanExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.GreaterThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.LessThanExpression, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.LessThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.GreaterThanExpression, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.GreaterThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison), new Operator(SyntaxKind.EqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), new Operator(SyntaxKind.NotEqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) }; - public Operator(SyntaxKind oper, OpFlags flags ) + private Operator(SyntaxKind oper, OpFlags flags) { Oper = oper; Flags = flags; diff --git a/Tree/Scope.cs b/Tree/Scope.cs new file mode 100644 index 0000000..87b736c --- /dev/null +++ b/Tree/Scope.cs @@ -0,0 +1,23 @@ +namespace Antigen.Tree +{ + /* + * Scopes need information about their "kind" - which construct pushed a new scope + * This information is used in parts of ExprGen that need to do backtracking - ex. + * the logic behind generating new label names + */ + public enum ScopeKind + { + ConditionalScope, //introduced by any "conditional" construct - try/catch, loops, if, switch + LoopScope, //introduced by any loops + GetterSetterScope, //introduced by getters, setters and other ImplicitCallKind + FunctionScope, //default, scope introduced by a new function + BracesScope //introduced by { } + } + + /// + /// Represents a scope + /// + public class Scope + { + } +} diff --git a/Tree/Statements.cs b/Tree/Statements.cs new file mode 100644 index 0000000..5da2e22 --- /dev/null +++ b/Tree/Statements.cs @@ -0,0 +1,11 @@ +namespace Antigen.Tree +{ + public enum StmtKind + { + VariableDeclaration, + } + + //public class Statements + //{ + //} +} diff --git a/Tree/Types.cs b/Tree/Types.cs new file mode 100644 index 0000000..f5b37e6 --- /dev/null +++ b/Tree/Types.cs @@ -0,0 +1,81 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System.Collections.Generic; + +namespace Antigen.Tree +{ + public enum TypeFlags + { + Numeric = 0x1, + Integer = 0x2, + Decimal = 0x4, + Char = 0x8, + String = 0x10, + Bool = 0x20, + } + + public enum ValueType + { + Boolean, + Byte, + Char, + Decimal, + Double, + Int16, + Int32, + Int64, + SByte, + Single, + String, + UInt16, + UInt32, + UInt64, + } + + public struct ExprType + { + // TODO: Matrix about implicit and explicit cast + + public bool HasFlag(TypeFlags flag) + { + bool val = (Flags & flag) != 0; + return val; + } + + public ValueType ValueType; + private TypeFlags Flags; + public SpecialType DataType; + public SyntaxKind TypeKind; + + private static readonly List types = new List() + { + new ExprType(ValueType.Boolean, SpecialType.System_Boolean, SyntaxKind.BoolKeyword, TypeFlags.Bool), + new ExprType(ValueType.Byte, SpecialType.System_Byte, SyntaxKind.ByteKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.Char, SpecialType.System_Char, SyntaxKind.CharKeyword, TypeFlags.Char), + new ExprType(ValueType.Decimal, SpecialType.System_Decimal, SyntaxKind.DecimalKeyword, TypeFlags.Numeric | TypeFlags.Decimal), + new ExprType(ValueType.Double, SpecialType.System_Double, SyntaxKind.DoubleKeyword, TypeFlags.Numeric | TypeFlags.Decimal), + new ExprType(ValueType.Int16, SpecialType.System_Int16, SyntaxKind.ShortKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.Int32, SpecialType.System_Int32, SyntaxKind.IntKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.Int64, SpecialType.System_Int64, SyntaxKind.LongKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.SByte, SpecialType.System_SByte, SyntaxKind.SByteKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.Single, SpecialType.System_Single, SyntaxKind.FloatKeyword, TypeFlags.Numeric | TypeFlags.Decimal), + new ExprType(ValueType.String, SpecialType.System_String, SyntaxKind.StringKeyword, TypeFlags.String), + new ExprType(ValueType.UInt16, SpecialType.System_UInt16, SyntaxKind.UShortKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.UInt32, SpecialType.System_UInt32, SyntaxKind.UIntKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ExprType(ValueType.UInt64, SpecialType.System_UInt64, SyntaxKind.ULongKeyword, TypeFlags.Numeric | TypeFlags.Integer), + }; + + private ExprType (ValueType valueType, SpecialType dataType, SyntaxKind typeKind, TypeFlags typeFlags) + { + ValueType = valueType; + DataType = dataType; + TypeKind = typeKind; + Flags = typeFlags; + } + + public static List GetTypes() + { + return types; + } + } +} From 7a91e4c67212fcaa316dad92a13f85542d3e1305 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 23 Dec 2020 03:14:38 -0800 Subject: [PATCH 004/149] x = y --- BaseMethod.cs | 53 +++++++++++++++++++++- ConfigOptions.cs | 1 + Program.cs | 2 +- README.md | 3 +- TestCase.cs | 17 ++++--- Tree/Expressions.cs | 3 +- Tree/Scope.cs | 106 +++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 174 insertions(+), 11 deletions(-) diff --git a/BaseMethod.cs b/BaseMethod.cs index b7a6c35..c2af7f5 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -14,6 +14,9 @@ public class BaseMethod private string Name; private List variableNames = new List(); + private Scope m_ParentScope; + private Stack ScopeStack = new Stack(); + public MethodDeclarationSyntax GeneratedMethod { get; private set;} public AstUtils GetASTUtils() @@ -21,6 +24,36 @@ public AstUtils GetASTUtils() return testCase.AstUtils; } + public void AddParentScope(Scope parent) + { + m_ParentScope = parent; + } + + public Scope GetParentScope() + { + if (m_ParentScope != null) + return m_ParentScope; + else + return null; + } + + public Scope CurrentScope + { + get { return ScopeStack.Peek(); } + } + + public void PushScope(Scope scope) + { + ScopeStack.Push(scope); + } + + public Scope PopScope() + { + Scope ret = ScopeStack.Pop(); + //Debug.Assert(ret.Parent == ScopeStack.Peek()); + return ret; + } + public BaseMethod(TestCase tc, string name) { testCase = tc; @@ -31,6 +64,19 @@ public void Generate() { MethodDeclarationSyntax methodDeclaration = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Name).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); IList methodBody = new List(); + + // TODO-TEMP initialize one variable of each type + foreach(ExprType variableType in ExprType.GetTypes()) + { + string variableName = Helpers.GetVariableName(variableType, variableNames.Count); + variableNames.Add(variableName); + + ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType); + CurrentScope.AddLocal(variableType, variableName); + + methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs))); + } + for (int i = 0; i < 10; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); @@ -56,7 +102,9 @@ public StatementSyntax StatementHelper(StmtKind stmtKind) variableNames.Add(variableName); ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpression(), variableType); - return SyntaxFactory.LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); + CurrentScope.AddLocal(variableType, variableName); + + return LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -71,7 +119,8 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, ExprType exprType) { case ExprKind.LiteralExpression: return Helpers.GetLiteralExpression(exprType); - + case ExprKind.VariableExpression: + return IdentifierName(CurrentScope.GetRandomVariable(exprType)); default: Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); break; diff --git a/ConfigOptions.cs b/ConfigOptions.cs index 8140828..db84873 100644 --- a/ConfigOptions.cs +++ b/ConfigOptions.cs @@ -15,6 +15,7 @@ public class ConfigOptions : OptionsBase // Expression weights public double LiteralWeight = 1; + public double VariableWeight = 1; // Statement weights public double VariableDeclarationWeight = 1; diff --git a/Program.cs b/Program.cs index ecd6478..d099b63 100644 --- a/Program.cs +++ b/Program.cs @@ -8,7 +8,7 @@ static void Main(string[] args) //GenerateTestCase(); int testId = 1; - while (true) + //while (true) { TestCase testCase = new TestCase(testId++); testCase.Generate(); diff --git a/README.md b/README.md index 5583fe5..cea370b 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,5 @@ Antigen C# test generator and RyuJIT tester - Named after Covid-19 antigen test. -1. Variable declaration where RHS is literal. \ No newline at end of file +1. Variable declaration where RHS is literal. +2. Introduce scopes so variables can be reused. \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 78484af..54a2f86 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -27,10 +27,11 @@ public enum CompilationType #region PreComputed roslyn syntax tress #endregion - private const string MainMethodName = "MainMethod"; + private const string MainMethodName = "Method0"; private SyntaxNode testClass; + private Scope GlobalScope; private List classesList; private List methodsList; private List propertiesList; @@ -47,16 +48,22 @@ public TestCase(int testId) public void Generate() { - BaseMethod mainMethod = new BaseMethod(this, MainMethodName); - mainMethod.Generate(); + GlobalScope = new Scope(this); - IList methods = new List() { mainMethod }; + IList methods = new List(); - for (int i = 1; i < 5; i++) + for (int i = 0; i < 5; i++) { var testMethod = new BaseMethod(this, "Method" + i); methods.Add(testMethod); + + Scope localScope = new Scope(this); + localScope.Parent = GlobalScope; + + testMethod.PushScope(localScope); + testMethod.Generate(); + testMethod.PopScope(); } ClassDeclarationSyntax klass = ClassDeclaration(Name).WithMembers(new SyntaxList(methods.Select(m => m.GeneratedMethod))); diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index d234a35..26bc0b3 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -2,7 +2,8 @@ { public enum ExprKind { - LiteralExpression + LiteralExpression, + VariableExpression, } //public struct Expression diff --git a/Tree/Scope.cs b/Tree/Scope.cs index 87b736c..e6391b7 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -1,4 +1,7 @@ -namespace Antigen.Tree +using System.Collections.Generic; +using System.Diagnostics; + +namespace Antigen.Tree { /* * Scopes need information about their "kind" - which construct pushed a new scope @@ -19,5 +22,106 @@ public enum ScopeKind /// public class Scope { + // Optional parent scope. + public Scope Parent = null; + public readonly ScopeKind ScopeType; + public TestCase TestCase; + + // Combines local variables, properties of members, and array properties. This is the + // only list from which GetRandom*Variable will draw -- the other lists are only to track + // variables so that the TestCase can initialize them and print them. + private Dictionary> ListOfVariables = new Dictionary>(); + + // List of local variables in current scope. + private Dictionary> LocalVariables = new Dictionary>(); + + // List of string vars in the current scope. + private List LocalStringVariables = new List(); + + #region Contructors + public Scope(TestCase tc) + { + TestCase = tc; + ScopeType = ScopeKind.FunctionScope; + } + + public Scope(ScopeKind t, TestCase tc) + { + TestCase = tc; + ScopeType = t; + } + + #endregion + + #region Get variables from the scope + public string GetRandomVariable(ExprType variableType) + { + List allUsableVariables = GetUsableVariables(variableType); + return allUsableVariables[PRNG.Next(allUsableVariables.Count)]; + } + #endregion + + #region Gets From Scope + public int GetVariablesCount() + { + return ListOfVariables.Count; + } + #endregion + + #region Add variables to scope + public void AddLocal(ExprType variableType, string variableName) + { +#if DEBUG + foreach (var valueType in LocalVariables.Keys) + { + Debug.Assert(!LocalVariables[valueType].Contains(variableName)); + } + + foreach (var valueType in ListOfVariables.Keys) + { + Debug.Assert(!ListOfVariables[valueType].Contains(variableName)); + } +#endif + // Add to local variables + if (!LocalVariables.ContainsKey(variableType)) + { + LocalVariables[variableType] = new List(); + } + + LocalVariables[variableType].Add(variableName); + + // Add to variables + if (!ListOfVariables.ContainsKey(variableType)) + { + ListOfVariables[variableType] = new List(); + } + + ListOfVariables[variableType].Add(variableName); + } + #endregion + + #region Aggregate Scopes methods + /// + /// Combines the list of Variables from all parent scopes. Respects strict mode restrictions + /// + /// + /// + private List GetUsableVariables(ExprType variableType) + { + List variables = new List(); + + Scope curr = this; + + while (curr != null) + { + if (curr.ListOfVariables.ContainsKey(variableType)) + { + variables.AddRange(curr.ListOfVariables[variableType]); + } + curr = curr.Parent; + } + return variables; + } + #endregion } } From e67a09c47cc154dbd541524c7126d8f163d4a891 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 24 Dec 2020 17:09:29 -0800 Subject: [PATCH 005/149] x op y --- Antigen.csproj | 6 +- Antigen.sln | 4 +- BaseMethod.cs | 47 +++++-- CSharpCompiler.cs | 117 ---------------- ConfigOptions.cs => Config/ConfigOptions.cs | 7 +- RunOptions.cs => Config/RunOptions.cs | 0 Helpers/Expressions.cs | 26 ++++ Helpers/Literals.cs | 36 ++--- Helpers/VariableDeclarationHelper.cs | 9 +- Program.cs | 7 +- README.md | 3 +- TestCase.cs | 23 +++- Tree/AstUtils.cs | 99 +++++++------ Tree/Expressions.cs | 1 + Tree/Operators.cs | 145 +++++++++++--------- Tree/Scope.cs | 10 +- Tree/Types.cs | 112 ++++++++------- 17 files changed, 331 insertions(+), 321 deletions(-) delete mode 100644 CSharpCompiler.cs rename ConfigOptions.cs => Config/ConfigOptions.cs (95%) rename RunOptions.cs => Config/RunOptions.cs (100%) create mode 100644 Helpers/Expressions.cs diff --git a/Antigen.csproj b/Antigen.csproj index c47db71..dbc857c 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -1,4 +1,4 @@ - + Exe @@ -13,4 +13,8 @@ + + diff --git a/Antigen.sln b/Antigen.sln index 9663912..45a0c62 100644 --- a/Antigen.sln +++ b/Antigen.sln @@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30410.220 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antigen", "Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Antigen", "Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FA00618-BD61-41BA-9044-1A08C274AA24}" ProjectSection(SolutionItems) = preProject - Operators.cs = Operators.cs + .editorconfig = .editorconfig EndProjectSection EndProject Global diff --git a/BaseMethod.cs b/BaseMethod.cs index c2af7f5..0e168a3 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -17,7 +17,7 @@ public class BaseMethod private Scope m_ParentScope; private Stack ScopeStack = new Stack(); - public MethodDeclarationSyntax GeneratedMethod { get; private set;} + public MethodDeclarationSyntax GeneratedMethod { get; private set; } public AstUtils GetASTUtils() { @@ -66,12 +66,12 @@ public void Generate() IList methodBody = new List(); // TODO-TEMP initialize one variable of each type - foreach(ExprType variableType in ExprType.GetTypes()) + foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { string variableName = Helpers.GetVariableName(variableType, variableNames.Count); variableNames.Add(variableName); - ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType); + ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs))); @@ -80,28 +80,29 @@ public void Generate() for (int i = 0; i < 10; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); - methodBody.Add(StatementHelper(cur)); + methodBody.Add(StatementHelper(cur, 0)); } // print all variables - foreach(string variableName in variableNames) + foreach (string variableName in variableNames) { methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); } - GeneratedMethod = methodDeclaration.WithBody(Block(methodBody)); + // Wrap everything in unchecked so we do not see overflow compilation errors + GeneratedMethod = methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); } - public StatementSyntax StatementHelper(StmtKind stmtKind) + public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { switch (stmtKind) { case StmtKind.VariableDeclaration: - ExprType variableType = GetASTUtils().GetRandomType(); + Tree.ValueType variableType = GetASTUtils().GetRandomExprType(); string variableName = Helpers.GetVariableName(variableType, variableNames.Count); variableNames.Add(variableName); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpression(), variableType); + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpression(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); return LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); @@ -113,7 +114,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind) return null; } - public ExpressionSyntax ExprHelper(ExprKind exprKind, ExprType exprType) + public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int depth) { switch (exprKind) { @@ -121,6 +122,32 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, ExprType exprType) return Helpers.GetLiteralExpression(exprType); case ExprKind.VariableExpression: return IdentifierName(CurrentScope.GetRandomVariable(exprType)); + case ExprKind.BinaryOpExpression: + Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); + + ////TODO-future: Use "" instead of exprType. so we can then do cast. + Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + Tree.ValueType rhsExprType = lhsExprType; + if (op.HasFlag(OpFlags.Shift)) + { + rhsExprType = GetASTUtils().GetRandomExprType(Primitive.Int32); + } + ExpressionSyntax lhs, rhs; + + //TODO-config: Add MaxDepth in config + if (depth >= 5) + { + lhs = ExprHelper(ExprKind.LiteralExpression, lhsExprType, 0); + rhs = ExprHelper(ExprKind.LiteralExpression, rhsExprType, 0); + } + else + { + lhs = ExprHelper(GetASTUtils().GetRandomExpression(lhsExprType.PrimitiveType), lhsExprType, depth + 1); + rhs = ExprHelper(GetASTUtils().GetRandomExpression(rhsExprType.PrimitiveType), rhsExprType, depth + 1); + } + + return Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)); + default: Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); break; diff --git a/CSharpCompiler.cs b/CSharpCompiler.cs deleted file mode 100644 index 2bcb9e8..0000000 --- a/CSharpCompiler.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Emit; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Exprgen -{ - internal static class CSharpCompiler - { - - private static readonly MetadataReference[] s_references = - { - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), - MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location), - MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), - // These two are needed to properly pick up System.Object when using methods on System.Console. - // See here: https://github.com/dotnet/corefx/issues/11601 - MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location), - MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Linq")).Location), - MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("mscorlib")).Location), - }; - - private static readonly CSharpCompilationOptions DebugOptions = - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Debug); - - private static readonly CSharpCompilationOptions ReleaseOptions = - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release); - - internal static void CompileAndExecute(string fileName) - { - string contents = File.ReadAllText(fileName); - CompilationUnitSyntax comp = SyntaxFactory.ParseCompilationUnit(contents, options: new CSharpParseOptions(LanguageVersion.Latest)); - //Console.WriteLine(comp.NormalizeWhitespace().ToFullString()); - - CompileResult compResult = Compile(comp); - if (compResult.Assembly == null) - { - Console.WriteLine("Got compiler errors:"); - Console.WriteLine(string.Join(Environment.NewLine, compResult.CompileErrors)); - } - else - { - Assembly asm = Assembly.Load(compResult.Assembly); - MethodInfo mainMethodInfo = asm.GetType("RyuJITTest").GetMethod("Main"); - Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); - - Exception ex = null; - //TextWriter origOut = Console.Out; - - MemoryStream ms = new MemoryStream(); - //StreamWriter sw = new StreamWriter(Console.s, Encoding.UTF8); - - try - { - //Console.SetOut(sw); - entryPoint(null); - } - catch (Exception caughtEx) - { - ex = caughtEx; - } - finally - { - //Console.SetOut(origOut); - //sw.Close(); - } - } - } - - private static CompileResult Compile(CompilationUnitSyntax program) - { - SyntaxTree[] trees = { SyntaxFactory.SyntaxTree(program, new CSharpParseOptions(LanguageVersion.Latest)) }; - CSharpCompilation comp = CSharpCompilation.Create("RyuJITTest", trees, s_references, ReleaseOptions); - - using (var ms = new MemoryStream()) - { - EmitResult result; - try - { - result = comp.Emit(ms); - } - catch (Exception ex) - { - return new CompileResult(ex, ImmutableArray.Empty, null); - } - - if (!result.Success) - return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null); - - return new CompileResult(null, ImmutableArray.Empty, ms.ToArray()); - } - } - } - - internal class CompileResult - { - public CompileResult(Exception roslynException, ImmutableArray compileErrors, byte[] assembly) - { - RoslynException = roslynException; - CompileErrors = compileErrors; - Assembly = assembly; - } - - public Exception RoslynException { get; } - public ImmutableArray CompileErrors { get; } - public byte[] Assembly { get; } - } - -} diff --git a/ConfigOptions.cs b/Config/ConfigOptions.cs similarity index 95% rename from ConfigOptions.cs rename to Config/ConfigOptions.cs index db84873..a456fa1 100644 --- a/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -14,8 +14,9 @@ public class ConfigOptions : OptionsBase public const string WeightSuffix = "Weight"; // Expression weights - public double LiteralWeight = 1; - public double VariableWeight = 1; + public double LiteralWeight = 0.25; + public double VariableWeight = 0.5; + public double BinaryOpWeight = 1; // Statement weights public double VariableDeclarationWeight = 1; @@ -82,7 +83,7 @@ public class ConfigOptions : OptionsBase public double EqualsWeight = 1; public double NotEqualsWeight = 1; - public double Lookup(ExprType type) + public double Lookup(Tree.ValueType type) { string str = Enum.GetName(typeof(Microsoft.CodeAnalysis.SpecialType), type.DataType); str = str.Replace("System_", ""); diff --git a/RunOptions.cs b/Config/RunOptions.cs similarity index 100% rename from RunOptions.cs rename to Config/RunOptions.cs diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs new file mode 100644 index 0000000..2411e1d --- /dev/null +++ b/Helpers/Expressions.cs @@ -0,0 +1,26 @@ +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using ValueType = Antigen.Tree.ValueType; + +namespace Antigen +{ + public static partial class Helpers + { + public static BinaryExpressionSyntax GetBinaryExpression(ExpressionSyntax lhs, Operator op, ExpressionSyntax rhs) + { + return BinaryExpression(op.Oper, lhs, rhs); + } + + public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueType returnType, ExpressionSyntax expr) + { + return ParenthesizedExpression(CastExpression(Helpers.GetToken(returnType.TypeKind), ParenthesizedExpression(expr))); + } + } +} diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index 639ef24..93dcaa0 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -92,13 +92,13 @@ public static decimal GetRandomDecimal() return (decimal)(PRNG.Next(int.MaxValue) + 3.5); } - public static LiteralExpressionSyntax GetLiteralExpression(ExprType literalType) + public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType literalType) { SyntaxToken literalToken; SyntaxKind kind; - switch (literalType.ValueType) + switch (literalType.PrimitiveType) { - case Tree.ValueType.Boolean: + case Tree.Primitive.Boolean: if (GetRandomBoolean()) { kind = SyntaxKind.TrueLiteralExpression; @@ -110,60 +110,60 @@ public static LiteralExpressionSyntax GetLiteralExpression(ExprType literalType) literalToken = Token(SyntaxKind.FalseKeyword); } break; - case Tree.ValueType.Byte: + case Tree.Primitive.Byte: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomByte()); break; - case Tree.ValueType.Char: + case Tree.Primitive.Char: kind = SyntaxKind.CharacterLiteralExpression; literalToken = Literal(GetRandomChar()); break; - case Tree.ValueType.Int16: + case Tree.Primitive.Int16: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomShort()); break; - case Tree.ValueType.Int32: + case Tree.Primitive.Int32: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomInt()); break; - case Tree.ValueType.Int64: + case Tree.Primitive.Int64: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomLong()); break; - case Tree.ValueType.UInt16: + case Tree.Primitive.UInt16: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomUShort()); break; - case Tree.ValueType.UInt32: + case Tree.Primitive.UInt32: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomUInt()); break; - case Tree.ValueType.UInt64: + case Tree.Primitive.UInt64: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomULong()); break; - case Tree.ValueType.SByte: + case Tree.Primitive.SByte: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomSByte()); break; - case Tree.ValueType.Single: + case Tree.Primitive.Single: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomFloat()); break; - case Tree.ValueType.Decimal: + case Tree.Primitive.Decimal: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomDecimal()); break; - case Tree.ValueType.Double: + case Tree.Primitive.Double: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomDouble()); break; - case Tree.ValueType.String: + case Tree.Primitive.String: kind = SyntaxKind.StringLiteralExpression; literalToken = Literal(GetRandomString()); break; default: - Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.ValueType), literalType.ValueType))); + Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(1); @@ -172,6 +172,8 @@ public static LiteralExpressionSyntax GetLiteralExpression(ExprType literalType) } return LiteralExpression(kind, literalToken); + + //return LiteralExpression(kind, literalToken); } } } diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs index eab04c4..4082f0f 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Helpers/VariableDeclarationHelper.cs @@ -14,7 +14,7 @@ namespace Antigen { public static partial class Helpers { - public static VariableDeclarationSyntax GetVariableDeclaration(ExprType variableType, string variableName, ExpressionSyntax value) + public static VariableDeclarationSyntax GetVariableDeclaration(Tree.ValueType variableType, string variableName, ExpressionSyntax value) { return VariableDeclaration( PredefinedType( @@ -27,9 +27,14 @@ public static VariableDeclarationSyntax GetVariableDeclaration(ExprType variable EqualsValueClause(value)))); } - public static string GetVariableName(ExprType variableType, int id) + public static string GetVariableName(Tree.ValueType variableType, int id) { return Enum.GetName(typeof(SpecialType), variableType.DataType).Replace("System_", "").ToLower() + "_" + id; } + + public static PredefinedTypeSyntax GetToken(SyntaxKind syntaxKind) + { + return PredefinedType(Token(syntaxKind)); + } } } diff --git a/Program.cs b/Program.cs index d099b63..813e034 100644 --- a/Program.cs +++ b/Program.cs @@ -1,4 +1,6 @@ -namespace Antigen +using System; + +namespace Antigen { class Program { @@ -6,9 +8,8 @@ static void Main(string[] args) { PRNG.Initialize(5); - //GenerateTestCase(); int testId = 1; - //while (true) + while (true) { TestCase testCase = new TestCase(testId++); testCase.Generate(); diff --git a/README.md b/README.md index cea370b..1b64297 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,5 @@ Antigen C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 1. Variable declaration where RHS is literal. -2. Introduce scopes so variables can be reused. \ No newline at end of file +2. Introduce scopes so variables can be reused. +3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 54a2f86..224c3ba 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -32,10 +32,10 @@ public enum CompilationType private SyntaxNode testClass; private Scope GlobalScope; - private List classesList; - private List methodsList; - private List propertiesList; - private List fieldsList; + //private List classesList; + //private List methodsList; + //private List propertiesList; + //private List fieldsList; public string Name { get; private set; } public AstUtils AstUtils { get; private set; } @@ -52,7 +52,7 @@ public void Generate() IList methods = new List(); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 1; i++) { var testMethod = new BaseMethod(this, "Method" + i); methods.Add(testMethod); @@ -61,7 +61,7 @@ public void Generate() localScope.Parent = GlobalScope; testMethod.PushScope(localScope); - + testMethod.Generate(); testMethod.PopScope(); } @@ -84,7 +84,15 @@ public void CompileAndExecute() private CompileResult Compile(CompilationType compilationType) { - Console.WriteLine(testClass.ToString()); + string testClassContents = testClass.ToFullString(); + File.WriteAllText(@"E:\git\Antigen\TestClass.g.cs", testClassContents); + + string[] testClassCode = testClassContents.Split(Environment.NewLine); + int lineNum = 1; + foreach (string code in testClassCode) + { + Console.WriteLine("[{0,4:D4}]{1}", lineNum++, code); + } string corelibPath = typeof(object).Assembly.Location; string otherAssembliesPath = Path.GetDirectoryName(corelibPath); @@ -125,6 +133,7 @@ private void Execute(CompileResult compileResult) { Console.WriteLine("Got compiler errors:"); Console.WriteLine(string.Join(Environment.NewLine, compileResult.CompileErrors)); + Console.ReadLine(); } else { diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 18dce3b..84f3295 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -7,12 +7,13 @@ namespace Antigen.Tree public class AstUtils { private List> AllExpressions = new List>(); + private List> AllNonNumericExpressions = new List>(); private List> AllStatements = new List>(); - private List> AllTypes = new List>(); - private List> AllStatementsWithCFStmts = new List>(); - private List> AllTerminalExpressions = new List>(); - private List> AllTerminalStatements = new List>(); - private List> AllTerminalStatementsWithCFStmts = new List>(); + private List> AllTypes = new List>(); + private List> AllStatementsWithCFStmts = new List>(); + private List> AllTerminalExpressions = new List>(); + private List> AllTerminalStatements = new List>(); + private List> AllTerminalStatementsWithCFStmts = new List>(); private List> AllOperators = new List>(); private ConfigOptions Options; @@ -26,9 +27,9 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) TestCase = tc; // Initialize types - foreach (ExprType type in ExprType.GetTypes()) + foreach (ValueType type in ValueType.GetTypes()) { - AllTypes.Add(new Weights(type, Options.Lookup(type))); + AllTypes.Add(new Weights(type, Options.Lookup(type))); } // Initialize statements @@ -41,6 +42,12 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) foreach (ExprKind expr in (ExprKind[])Enum.GetValues(typeof(ExprKind))) { AllExpressions.Add(new Weights(expr, Options.Lookup(expr))); + // For binary operation, there is no operator that don't have assign flag and that returns char or string + // Hence do not choose binary expression if return is expected to be string + if (expr != ExprKind.BinaryOpExpression) + { + AllNonNumericExpressions.Add(new Weights(expr, Options.Lookup(expr))); + } } // Initialize operators @@ -51,26 +58,48 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) } #region Random type methods - public ExprType GetRandomType() + public ValueType GetRandomExprType() { - // Select all appropriate statements - IEnumerable> types = + // Select all appropriate types + IEnumerable> types = + from z in AllTypes + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(types); + } + + public ValueType GetRandomExprType(Primitive valueType) + { + // Select all appropriate types + IEnumerable> types = from z in AllTypes + where z.Data.AllowedPrimitive(valueType) select z; // Do a weighted random choice. return PRNG.WeightedChoice(types); } + #endregion - #region Random statement methods + #region Random expression methods - public ExprKind GetRandomExpression() + //TODO-verify: Should this also take ExprType? + public ExprKind GetRandomExpression(Primitive returnPrimitiveType) { - // Select all appropriate statements - IEnumerable> exprs = - from z in AllExpressions - select z; + IEnumerable> exprs; + // Select all appropriate expressions + if (returnPrimitiveType == Primitive.Char) + { + exprs = from z in AllNonNumericExpressions + select z; + } + else + { + exprs = from z in AllExpressions + select z; + } // Do a weighted random choice. return PRNG.WeightedChoice(exprs); @@ -95,12 +124,12 @@ from z in AllStatements #region Random operator methods - public Operator GetRandomBinaryOperator() + public Operator GetRandomBinaryOperator(Primitive returnPrimitiveType) { // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.Binary) && !z.Data.HasFlag(Operator.OpFlags.Assignment) + where z.Data.HasFlag(OpFlags.Binary) && !z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnPrimitiveType) select z; // Do a weighted random choice. @@ -112,20 +141,12 @@ public Operator GetRandomComparisonOperator() // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.Comparison) + where z.Data.HasFlag(OpFlags.Comparison) where z.Weight != 0 select z; - // If we've disabled all comparison operators, just use another binary operator. - if (ops.Count() == 0) - { - return GetRandomBinaryOperator(); - } - else - { - // Do a weighted random choice. - return PRNG.WeightedChoice(ops); - } + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); } public Operator GetRandomLogicalOperator() @@ -133,20 +154,12 @@ public Operator GetRandomLogicalOperator() // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.Logical) + where z.Data.HasFlag(OpFlags.Logical) where z.Weight != 0 select z; - // If we've disabled all comparison operators, just use another binary operator. - if (ops.Count() == 0) - { - return GetRandomBinaryOperator(); - } - else - { - // Do a weighted random choice. - return PRNG.WeightedChoice(ops); - } + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); } public Operator GetRandomUnaryOperator() @@ -154,7 +167,7 @@ public Operator GetRandomUnaryOperator() // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.Unary) + where z.Data.HasFlag(OpFlags.Unary) select z; // Do a weighted random choice. @@ -166,7 +179,7 @@ public Operator GetRandomAssignmentOperator() // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.Assignment) + where z.Data.HasFlag(OpFlags.Assignment) select z; // Do a weighted random choice. @@ -178,7 +191,7 @@ public Operator GetRandomStringOperator() // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(Operator.OpFlags.String) + where z.Data.HasFlag(OpFlags.String) select z; // Do a weighted random choice. diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index 26bc0b3..8973827 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -4,6 +4,7 @@ public enum ExprKind { LiteralExpression, VariableExpression, + BinaryOpExpression, } //public struct Expression diff --git a/Tree/Operators.cs b/Tree/Operators.cs index 6470beb..46e7ece 100644 --- a/Tree/Operators.cs +++ b/Tree/Operators.cs @@ -1,30 +1,35 @@ -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using System.Collections.Generic; namespace Antigen.Tree { + public enum OpFlags + { + Comparison = 0x1, + Binary = 0x2, + Unary = 0x4, + Divide = 0x8, + Shift = 0x10, + IncrementDecrement = 0x20, + Math = 0x40, + Assignment = 0x80, + Logical = 0x100, + Bitwise = 0x200, + String = 0x400, + } + public struct Operator { - public enum OpFlags - { - Comparison = 0x1, - Binary = 0x2, - Unary = 0x4, - Divide = 0x8, - Shift = 0x10, - IncrementDecrement = 0x20, - Math = 0x40, - Assignment = 0x80, - Logical = 0x100, - Bitwise = 0x200, - String = 0x400, - Yield = 0x800 - } //public string Name => Oper.ToString(); + + public OpFlags Flags; + public Primitive InputTypes; + public Primitive ReturnType; public SyntaxKind Oper; + private string renderText; public bool HasFlag(OpFlags flag) { @@ -32,57 +37,68 @@ public bool HasFlag(OpFlags flag) return val; } + public bool HasReturnType(Primitive valueType) + { + bool val = (ReturnType & valueType) != 0; + return val; + } + private static readonly List operators = new List() { - new Operator(SyntaxKind.UnaryPlusExpression, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.UnaryMinusExpression, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.PreIncrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PreDecrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostIncrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostDecrementExpression, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.LogicalNotExpression, OpFlags.Unary), - new Operator(SyntaxKind.BitwiseNotExpression, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.TypeOfExpression, OpFlags.Unary), - - new Operator(SyntaxKind.AddExpression, OpFlags.Binary | OpFlags.Math | OpFlags.String), - new Operator(SyntaxKind.SubtractExpression, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.MultiplyExpression, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.DivideExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), - new Operator(SyntaxKind.ModuloExpression, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.LeftShiftExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), - new Operator(SyntaxKind.RightShiftExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), - - new Operator(SyntaxKind.SimpleAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.AddAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), - new Operator(SyntaxKind.SubtractAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.MultiplyAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.DivideAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), - new Operator(SyntaxKind.ModuloAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.LeftShiftAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - new Operator(SyntaxKind.RightShiftAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - - new Operator(SyntaxKind.LogicalAndExpression, OpFlags.Binary | OpFlags.Logical), - new Operator(SyntaxKind.LogicalOrExpression, OpFlags.Binary | OpFlags.Logical), - - new Operator(SyntaxKind.BitwiseAndExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.BitwiseOrExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.ExclusiveOrExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - - new Operator(SyntaxKind.AndAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.OrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - - new Operator(SyntaxKind.LessThanExpression, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.LessThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.GreaterThanExpression, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.GreaterThanOrEqualExpression, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.EqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.NotEqualsExpression, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) + new Operator(SyntaxKind.UnaryPlusExpression, "+i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.UnaryMinusExpression, "-i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.PreIncrementExpression, "++i", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PreDecrementExpression, "--i", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostIncrementExpression, "i++", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostDecrementExpression, "i--", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.LogicalNotExpression, "!i", Primitive.Boolean, Primitive.Boolean, OpFlags.Unary | OpFlags.Logical), + new Operator(SyntaxKind.BitwiseNotExpression, "~i", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), + //new Operator(SyntaxKind.TypeOfExpression, "typeof(i)", OpFlags.Unary), + + new Operator(SyntaxKind.AddExpression, "i+j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.String), + new Operator(SyntaxKind.AddExpression, "i concat j", Primitive.String, Primitive.String, OpFlags.Binary | OpFlags.String), + new Operator(SyntaxKind.SubtractExpression, "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.MultiplyExpression, "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.DivideExpression, "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), + new Operator(SyntaxKind.ModuloExpression, "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.LeftShiftExpression, "i<>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), + + new Operator(SyntaxKind.SimpleAssignmentExpression, "i=j", Primitive.Any, Primitive.Any, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.AddAssignmentExpression, "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), + new Operator(SyntaxKind.SubtractAssignmentExpression, "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.MultiplyAssignmentExpression, "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.DivideAssignmentExpression, "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), + new Operator(SyntaxKind.ModuloAssignmentExpression, "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.LeftShiftAssignmentExpression, "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + new Operator(SyntaxKind.RightShiftAssignmentExpression, "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + + new Operator(SyntaxKind.LogicalAndExpression, "i&&j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + new Operator(SyntaxKind.LogicalOrExpression, "i||j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + + //TODO: below can also be logical as per https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators + new Operator(SyntaxKind.BitwiseAndExpression, "i&j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.BitwiseOrExpression, "i|j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.ExclusiveOrExpression, "i^j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + + new Operator(SyntaxKind.AndAssignmentExpression, "i&=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.OrAssignmentExpression, "i|=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, "i^=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + + new Operator(SyntaxKind.LessThanExpression, "ij", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.GreaterThanOrEqualExpression, "i>=j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.EqualsExpression, "i==j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.NotEqualsExpression, "i!=j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) }; - private Operator(SyntaxKind oper, OpFlags flags) + private Operator(SyntaxKind oper, string text, Primitive inputTypes, Primitive outputType, OpFlags flags) { Oper = oper; + renderText = text; + InputTypes = inputTypes; + ReturnType = outputType; Flags = flags; } @@ -90,5 +106,10 @@ public static List GetOperators() { return operators; } + + public override string ToString() + { + return renderText; + } } -} \ No newline at end of file +} diff --git a/Tree/Scope.cs b/Tree/Scope.cs index e6391b7..731e694 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -30,10 +30,10 @@ public class Scope // Combines local variables, properties of members, and array properties. This is the // only list from which GetRandom*Variable will draw -- the other lists are only to track // variables so that the TestCase can initialize them and print them. - private Dictionary> ListOfVariables = new Dictionary>(); + private Dictionary> ListOfVariables = new Dictionary>(); // List of local variables in current scope. - private Dictionary> LocalVariables = new Dictionary>(); + private Dictionary> LocalVariables = new Dictionary>(); // List of string vars in the current scope. private List LocalStringVariables = new List(); @@ -54,7 +54,7 @@ public Scope(ScopeKind t, TestCase tc) #endregion #region Get variables from the scope - public string GetRandomVariable(ExprType variableType) + public string GetRandomVariable(ValueType variableType) { List allUsableVariables = GetUsableVariables(variableType); return allUsableVariables[PRNG.Next(allUsableVariables.Count)]; @@ -69,7 +69,7 @@ public int GetVariablesCount() #endregion #region Add variables to scope - public void AddLocal(ExprType variableType, string variableName) + public void AddLocal(ValueType variableType, string variableName) { #if DEBUG foreach (var valueType in LocalVariables.Keys) @@ -106,7 +106,7 @@ public void AddLocal(ExprType variableType, string variableName) /// /// /// - private List GetUsableVariables(ExprType variableType) + private List GetUsableVariables(ValueType variableType) { List variables = new List(); diff --git a/Tree/Types.cs b/Tree/Types.cs index f5b37e6..6e0e3d2 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -1,81 +1,97 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using System; using System.Collections.Generic; namespace Antigen.Tree { - public enum TypeFlags - { - Numeric = 0x1, - Integer = 0x2, - Decimal = 0x4, - Char = 0x8, - String = 0x10, - Bool = 0x20, - } + //public enum TypeFlags : ulong + //{ + // Void = 0x0, + // Numeric = Primitive.Byte | Primitive.Decimal | Primitive.Double | Primitive.Int16 | Primitive.Int32 | Primitive.Int64 | Primitive.SByte | Primitive.Single | Primitive.UInt16 | Primitive.UInt32 | Primitive.UInt64, + // Integer = Primitive.Byte | Primitive.SByte | Primitive.Int16 | Primitive.Int32 | Primitive.Int64 | Primitive.UInt16 | Primitive.UInt32 | Primitive.UInt64, + // Decimal = Primitive.Single | Primitive.Double | Primitive.Decimal, + // Char = Primitive.Char, + // String = Primitive.String, + // Bool = Primitive.Boolean, + // Any = Numeric | Char | String | Bool, + //} - public enum ValueType + public enum Primitive : ulong { - Boolean, - Byte, - Char, - Decimal, - Double, - Int16, - Int32, - Int64, - SByte, - Single, - String, - UInt16, - UInt32, - UInt64, + Void = 0x0, + + Boolean = 0x1, + Byte = 0x2, + Char = 0x4, + Decimal = 0x8, + Double = 0x10, + Int16 = 0x20, + Int32 = 0x40, + Int64 = 0x80, + SByte = 0x100, + Single = 0x200, + String = 0x400, + UInt16 = 0x800, + UInt32 = 0x1000, + UInt64 = 0x2000, + + Numeric = Byte | Decimal | Double | Int16 | Int32 | Int64 | SByte | Single | UInt16 | UInt32 | UInt64, + SignedInteger = SByte | Int16 | Int32 | Int64, + UnsignedInteger = Byte | UInt16 | UInt32 | UInt64, + Integer = SignedInteger | UnsignedInteger, + FloatingPoint = Single | Double | Decimal, + Any = Numeric | Char | String | Boolean, } - public struct ExprType + public struct ValueType { // TODO: Matrix about implicit and explicit cast - public bool HasFlag(TypeFlags flag) + public bool AllowedPrimitive(Primitive primitives) { - bool val = (Flags & flag) != 0; + bool val = (primitives & PrimitiveType) != 0; return val; } - public ValueType ValueType; - private TypeFlags Flags; + public Primitive PrimitiveType; + //private TypeFlags Flags; public SpecialType DataType; public SyntaxKind TypeKind; - private static readonly List types = new List() + private static readonly List types = new List() { - new ExprType(ValueType.Boolean, SpecialType.System_Boolean, SyntaxKind.BoolKeyword, TypeFlags.Bool), - new ExprType(ValueType.Byte, SpecialType.System_Byte, SyntaxKind.ByteKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.Char, SpecialType.System_Char, SyntaxKind.CharKeyword, TypeFlags.Char), - new ExprType(ValueType.Decimal, SpecialType.System_Decimal, SyntaxKind.DecimalKeyword, TypeFlags.Numeric | TypeFlags.Decimal), - new ExprType(ValueType.Double, SpecialType.System_Double, SyntaxKind.DoubleKeyword, TypeFlags.Numeric | TypeFlags.Decimal), - new ExprType(ValueType.Int16, SpecialType.System_Int16, SyntaxKind.ShortKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.Int32, SpecialType.System_Int32, SyntaxKind.IntKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.Int64, SpecialType.System_Int64, SyntaxKind.LongKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.SByte, SpecialType.System_SByte, SyntaxKind.SByteKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.Single, SpecialType.System_Single, SyntaxKind.FloatKeyword, TypeFlags.Numeric | TypeFlags.Decimal), - new ExprType(ValueType.String, SpecialType.System_String, SyntaxKind.StringKeyword, TypeFlags.String), - new ExprType(ValueType.UInt16, SpecialType.System_UInt16, SyntaxKind.UShortKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.UInt32, SpecialType.System_UInt32, SyntaxKind.UIntKeyword, TypeFlags.Numeric | TypeFlags.Integer), - new ExprType(ValueType.UInt64, SpecialType.System_UInt64, SyntaxKind.ULongKeyword, TypeFlags.Numeric | TypeFlags.Integer), + new ValueType(Primitive.Boolean, SpecialType.System_Boolean, SyntaxKind.BoolKeyword), + new ValueType(Primitive.Byte, SpecialType.System_Byte, SyntaxKind.ByteKeyword), + new ValueType(Primitive.Char, SpecialType.System_Char, SyntaxKind.CharKeyword), + new ValueType(Primitive.Decimal, SpecialType.System_Decimal, SyntaxKind.DecimalKeyword), + new ValueType(Primitive.Double, SpecialType.System_Double, SyntaxKind.DoubleKeyword), + new ValueType(Primitive.Int16, SpecialType.System_Int16, SyntaxKind.ShortKeyword), + new ValueType(Primitive.Int32, SpecialType.System_Int32, SyntaxKind.IntKeyword), + new ValueType(Primitive.Int64, SpecialType.System_Int64, SyntaxKind.LongKeyword), + new ValueType(Primitive.SByte, SpecialType.System_SByte, SyntaxKind.SByteKeyword), + new ValueType(Primitive.Single, SpecialType.System_Single, SyntaxKind.FloatKeyword), + new ValueType(Primitive.String, SpecialType.System_String, SyntaxKind.StringKeyword), + new ValueType(Primitive.UInt16, SpecialType.System_UInt16, SyntaxKind.UShortKeyword), + new ValueType(Primitive.UInt32, SpecialType.System_UInt32, SyntaxKind.UIntKeyword), + new ValueType(Primitive.UInt64, SpecialType.System_UInt64, SyntaxKind.ULongKeyword), }; - private ExprType (ValueType valueType, SpecialType dataType, SyntaxKind typeKind, TypeFlags typeFlags) + private ValueType(Primitive valueType, SpecialType dataType, SyntaxKind typeKind) { - ValueType = valueType; + PrimitiveType = valueType; DataType = dataType; TypeKind = typeKind; - Flags = typeFlags; } - public static List GetTypes() + public static List GetTypes() { return types; } + + public override string ToString() + { + return Enum.GetName(typeof(Primitive), PrimitiveType); + } } } From 9575aca11ac70cb1463b8edd971d1237754747d2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 24 Dec 2020 17:11:16 -0800 Subject: [PATCH 006/149] Add .editorconfig --- .editorconfig | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 3 +- 2 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3ddcd7b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,276 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Powershell files +[*.ps1] +indent_size = 2 + +# Shell script files +[*.sh] +end_of_line = lf +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# IDE0055: Fix formatting +dotnet_diagnostic.IDE0055.severity = warning + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Non-private readonly fields are PascalCase +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style + +dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly + +dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Static fields are camelCase and start with s_ +dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields +dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_field_style.capitalization = camel_case +dotnet_naming_style.static_field_style.required_prefix = s_ + +# Instance fields are camelCase and start with _ +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case +dotnet_naming_style.instance_field_style.required_prefix = _ + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}' +dotnet_diagnostic.RS2008.severity = none + +# IDE0073: File header +dotnet_diagnostic.IDE0073.severity = warning +file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.\nSee the LICENSE file in the project root for more information. + +# IDE0035: Remove unreachable code +dotnet_diagnostic.IDE0035.severity = warning + +# IDE0036: Order modifiers +dotnet_diagnostic.IDE0036.severity = warning + +# IDE0043: Format string contains invalid placeholder +dotnet_diagnostic.IDE0043.severity = warning + +# IDE0044: Make field readonly +dotnet_diagnostic.IDE0044.severity = warning + +# RS0016: Only enable if API files are present +dotnet_public_api_analyzer.require_api_files = true + +# CSharp code style settings: +[*.cs] +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Blocks are allowed +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +[src/CodeStyle/**.{cs,vb}] +# warning RS0005: Do not use generic CodeAction.Create to create CodeAction +dotnet_diagnostic.RS0005.severity = none + +[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures, VisualStudio}/**/*.{cs,vb}] + +# IDE0011: Add braces +csharp_prefer_braces = when_multiline:warning +# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings? +# IDE0051: Remove unused private member +dotnet_diagnostic.IDE0051.severity = warning + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = warning + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning + +# Prefer "var" everywhere +dotnet_diagnostic.IDE0007.severity = warning +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning + +[src/{VisualStudio}/**/*.{cs,vb}] +# CA1822: Make member static +# Not enforced as a build 'warning' for 'VisualStudio' layer due to large number of false positives from https://github.com/dotnet/roslyn-analyzers/issues/3857 and https://github.com/dotnet/roslyn-analyzers/issues/3858 +# Additionally, there is a risk of accidentally breaking an internal API that partners rely on though IVT. +dotnet_diagnostic.CA1822.severity = suggestion \ No newline at end of file diff --git a/.gitignore b/.gitignore index f677870..854dc0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ bin obj -.vs \ No newline at end of file +.vs +**\*.g.cs \ No newline at end of file From ddf050248b12dab80ebf7d880786ae5a45eba2bd Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 24 Dec 2020 18:00:55 -0800 Subject: [PATCH 007/149] if (cond) { ... } else { ... } --- BaseMethod.cs | 59 ++++++++++++++++++++++++++++++++++++++--- Config/ConfigOptions.cs | 3 ++- README.md | 3 ++- TestCase.cs | 3 +-- Tree/Scope.cs | 10 ++++--- Tree/Statements.cs | 1 + Tree/Types.cs | 6 +++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/BaseMethod.cs b/BaseMethod.cs index 0e168a3..7ed3554 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -84,7 +84,7 @@ public void Generate() } // print all variables - foreach (string variableName in variableNames) + foreach (string variableName in CurrentScope.AllVariables) { methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); } @@ -107,6 +107,57 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); + case StmtKind.IfElseStatement: + + Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); + ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpression(Primitive.Boolean), condValueType, 0); + + Scope ifBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); + Scope elseBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); + + //TODO-config: Add MaxDepth in config + int ifcount = 3; + IList ifBody = new List(); + + PushScope(ifBranchScope); + for (int i = 0; i < ifcount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + ifBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'if' body scope + + int elsecount = 3; + IList elseBody = new List(); + + PushScope(elseBranchScope); + for (int i = 0; i < elsecount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + elseBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'else' body scope + + return IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))); + default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; @@ -120,17 +171,18 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i { case ExprKind.LiteralExpression: return Helpers.GetLiteralExpression(exprType); + case ExprKind.VariableExpression: return IdentifierName(CurrentScope.GetRandomVariable(exprType)); + case ExprKind.BinaryOpExpression: Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); - ////TODO-future: Use "" instead of exprType. so we can then do cast. Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); Tree.ValueType rhsExprType = lhsExprType; if (op.HasFlag(OpFlags.Shift)) { - rhsExprType = GetASTUtils().GetRandomExprType(Primitive.Int32); + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int32); } ExpressionSyntax lhs, rhs; @@ -145,7 +197,6 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i lhs = ExprHelper(GetASTUtils().GetRandomExpression(lhsExprType.PrimitiveType), lhsExprType, depth + 1); rhs = ExprHelper(GetASTUtils().GetRandomExpression(rhsExprType.PrimitiveType), rhsExprType, depth + 1); } - return Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)); default: diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index a456fa1..7c2ca75 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -19,7 +19,8 @@ public class ConfigOptions : OptionsBase public double BinaryOpWeight = 1; // Statement weights - public double VariableDeclarationWeight = 1; + public double VariableDeclarationWeight = 0.5; + public double IfElseStatementWeight = 1; // Type weights public double BooleanWeight = 1; diff --git a/README.md b/README.md index 1b64297..8f75772 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 1. Variable declaration where RHS is literal. 2. Introduce scopes so variables can be reused. -3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' \ No newline at end of file +3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' +4. Added if-else statement \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 224c3ba..f6a3f8d 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -57,8 +57,7 @@ public void Generate() var testMethod = new BaseMethod(this, "Method" + i); methods.Add(testMethod); - Scope localScope = new Scope(this); - localScope.Parent = GlobalScope; + Scope localScope = new Scope(this, ScopeKind.FunctionScope, GlobalScope); testMethod.PushScope(localScope); diff --git a/Tree/Scope.cs b/Tree/Scope.cs index 731e694..80aa25c 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Linq; namespace Antigen.Tree { @@ -23,7 +24,7 @@ public enum ScopeKind public class Scope { // Optional parent scope. - public Scope Parent = null; + private Scope parent = null; public readonly ScopeKind ScopeType; public TestCase TestCase; @@ -35,6 +36,8 @@ public class Scope // List of local variables in current scope. private Dictionary> LocalVariables = new Dictionary>(); + public List AllVariables => LocalVariables.SelectMany(dict => dict.Value).ToList(); + // List of string vars in the current scope. private List LocalStringVariables = new List(); @@ -45,10 +48,11 @@ public Scope(TestCase tc) ScopeType = ScopeKind.FunctionScope; } - public Scope(ScopeKind t, TestCase tc) + public Scope(TestCase tc, ScopeKind t, Scope parentScope) { TestCase = tc; ScopeType = t; + parent = parentScope; } #endregion @@ -118,7 +122,7 @@ private List GetUsableVariables(ValueType variableType) { variables.AddRange(curr.ListOfVariables[variableType]); } - curr = curr.Parent; + curr = curr.parent; } return variables; } diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 5da2e22..e12711c 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -3,6 +3,7 @@ public enum StmtKind { VariableDeclaration, + IfElseStatement, } //public class Statements diff --git a/Tree/Types.cs b/Tree/Types.cs index 6e0e3d2..713aa5f 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using System; using System.Collections.Generic; +using System.Linq; namespace Antigen.Tree { @@ -89,6 +90,11 @@ public static List GetTypes() return types; } + public static ValueType ForPrimitive(Primitive primitiveType) + { + return types.First(t => t.PrimitiveType == primitiveType); + } + public override string ToString() { return Enum.GetName(typeof(Primitive), PrimitiveType); From e71bf6dad10c491ebc18298aae78aa2be7df3fa2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 24 Dec 2020 23:56:40 -0800 Subject: [PATCH 008/149] x = y /* S:Assign */ --- BaseMethod.cs | 134 +++++++++++++++++++++++++--------------- Config/ConfigOptions.cs | 1 + README.md | 3 +- Tree/AstUtils.cs | 14 ++++- Tree/Statements.cs | 1 + 5 files changed, 100 insertions(+), 53 deletions(-) diff --git a/BaseMethod.cs b/BaseMethod.cs index 7ed3554..5548b0b 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -1,4 +1,5 @@ using Antigen.Tree; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; @@ -12,6 +13,11 @@ public class BaseMethod { private TestCase testCase; private string Name; +#if DEBUG + private bool annotateComments = true; +#else + private bool annotateComments = false; +#endif private List variableNames = new List(); private Scope m_ParentScope; @@ -98,65 +104,77 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) switch (stmtKind) { case StmtKind.VariableDeclaration: - Tree.ValueType variableType = GetASTUtils().GetRandomExprType(); - string variableName = Helpers.GetVariableName(variableType, variableNames.Count); - variableNames.Add(variableName); + { + Tree.ValueType variableType = GetASTUtils().GetRandomExprType(); + string variableName = Helpers.GetVariableName(variableType, variableNames.Count); + variableNames.Add(variableName); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpression(variableType.PrimitiveType), variableType, 0); - CurrentScope.AddLocal(variableType, variableName); + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); + CurrentScope.AddLocal(variableType, variableName); - return LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)); + return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "S:VarDecl"); + } case StmtKind.IfElseStatement: + { + Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); + ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); - Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); - ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpression(Primitive.Boolean), condValueType, 0); - - Scope ifBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); - Scope elseBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); - - //TODO-config: Add MaxDepth in config - int ifcount = 3; - IList ifBody = new List(); + Scope ifBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); + Scope elseBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); - PushScope(ifBranchScope); - for (int i = 0; i < ifcount; i++) - { - StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) - { - cur = StmtKind.VariableDeclaration; - } - else + int ifcount = 3; + IList ifBody = new List(); + + PushScope(ifBranchScope); + for (int i = 0; i < ifcount; i++) { - cur = GetASTUtils().GetRandomStatemet(); + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + ifBody.Add(StatementHelper(cur, depth + 1)); } - ifBody.Add(StatementHelper(cur, depth + 1)); - } - PopScope(); // pop 'if' body scope + PopScope(); // pop 'if' body scope - int elsecount = 3; - IList elseBody = new List(); + int elsecount = 3; + IList elseBody = new List(); - PushScope(elseBranchScope); - for (int i = 0; i < elsecount; i++) - { - StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= 2) - { - cur = StmtKind.VariableDeclaration; - } - else + PushScope(elseBranchScope); + for (int i = 0; i < elsecount; i++) { - cur = GetASTUtils().GetRandomStatemet(); + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + elseBody.Add(StatementHelper(cur, depth + 1)); } - elseBody.Add(StatementHelper(cur, depth + 1)); + PopScope(); // pop 'else' body scope + + return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "S:IfElse"); } - PopScope(); // pop 'else' body scope - return IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))); + case StmtKind.AssignStatement: + { + Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); + Tree.ValueType variableType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, variableType, depth); + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, depth); + return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "S:Assign"); + } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -170,10 +188,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i switch (exprKind) { case ExprKind.LiteralExpression: - return Helpers.GetLiteralExpression(exprType); + return Annotate(Helpers.GetLiteralExpression(exprType), "E:Literal"); case ExprKind.VariableExpression: - return IdentifierName(CurrentScope.GetRandomVariable(exprType)); + return Annotate(IdentifierName(CurrentScope.GetRandomVariable(exprType)), "E:Var"); case ExprKind.BinaryOpExpression: Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); @@ -194,10 +212,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } else { - lhs = ExprHelper(GetASTUtils().GetRandomExpression(lhsExprType.PrimitiveType), lhsExprType, depth + 1); - rhs = ExprHelper(GetASTUtils().GetRandomExpression(rhsExprType.PrimitiveType), rhsExprType, depth + 1); + lhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType), lhsExprType, depth + 1); + rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth + 1); } - return Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)); + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "E:BinOp"); default: Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); @@ -205,5 +223,23 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } return null; } + + private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) + { + if (!annotateComments) + { + return expression; + } + return expression.WithTrailingTrivia(TriviaList(Comment("/* " + comment + " */"))); + } + + private StatementSyntax Annotate(StatementSyntax statement, string comment) + { + if (!annotateComments) + { + return statement; + } + return statement.WithTrailingTrivia(TriviaList(Comment("/* " + comment + " */"))); + } } } diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 7c2ca75..4dbb8bf 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -21,6 +21,7 @@ public class ConfigOptions : OptionsBase // Statement weights public double VariableDeclarationWeight = 0.5; public double IfElseStatementWeight = 1; + public double AssignStatementWeight = 1; // Type weights public double BooleanWeight = 1; diff --git a/README.md b/README.md index 8f75772..418aca0 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 1. Variable declaration where RHS is literal. 2. Introduce scopes so variables can be reused. 3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' -4. Added if-else statement \ No newline at end of file +4. Added if-else statement +5. Assignment statement, /* S:Assign */ annotation \ No newline at end of file diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 84f3295..d8a2076 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -85,8 +85,17 @@ where z.Data.AllowedPrimitive(valueType) #region Random expression methods - //TODO-verify: Should this also take ExprType? - public ExprKind GetRandomExpression(Primitive returnPrimitiveType) + public ExprKind GetRandomExpression() + { + IEnumerable> exprs = + from z in AllExpressions + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(exprs); + } + + public ExprKind GetRandomExpressionReturningPrimitive(Primitive returnPrimitiveType) { IEnumerable> exprs; // Select all appropriate expressions @@ -104,7 +113,6 @@ public ExprKind GetRandomExpression(Primitive returnPrimitiveType) // Do a weighted random choice. return PRNG.WeightedChoice(exprs); } - #endregion #region Random statement methods diff --git a/Tree/Statements.cs b/Tree/Statements.cs index e12711c..0123467 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -4,6 +4,7 @@ public enum StmtKind { VariableDeclaration, IfElseStatement, + AssignStatement, } //public class Statements From be7f632221920a5564be9174c967527a5083fcaa Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 25 Dec 2020 03:09:47 -0800 Subject: [PATCH 009/149] for (...) { .. } --- BaseMethod.cs | 56 ++- Config/ConfigOptions.cs | 27 +- Helpers/Constants.cs | 17 + Program.cs | 2 +- README.md | 3 +- Statements/ForStatement.cs | 190 ++++++++++ Statements/LoopStatement.cs | 720 ++++++++++++++++++++++++++++++++++++ Tree/AstUtils.cs | 41 ++ Tree/Operators.cs | 6 + Tree/Statements.cs | 1 + 10 files changed, 1056 insertions(+), 7 deletions(-) create mode 100644 Helpers/Constants.cs create mode 100644 Statements/ForStatement.cs create mode 100644 Statements/LoopStatement.cs diff --git a/BaseMethod.cs b/BaseMethod.cs index 5548b0b..f4c693e 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -1,4 +1,5 @@ -using Antigen.Tree; +using Antigen.Statements; +using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -83,6 +84,14 @@ public void Generate() methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs))); } + //TODO: Define some more constants + methodBody.Add( + LocalDeclarationStatement( + Helpers.GetVariableDeclaration( + Tree.ValueType.ForPrimitive(Primitive.Int32), + Constants.LoopInvariantName, + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10)))))); + for (int i = 0; i < 10; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); @@ -114,7 +123,6 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "S:VarDecl"); } - case StmtKind.IfElseStatement: { Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); @@ -166,7 +174,6 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "S:IfElse"); } - case StmtKind.AssignStatement: { Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); @@ -175,7 +182,50 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, depth); return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "S:Assign"); } + case StmtKind.ForStatement: + { + Scope forLoopScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); + ForStatement forStmt = new ForStatement(testCase); + //TODO:config + int n = 3; // max statements + forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int32)); + forStmt.NestNum = depth; + forStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + + // 50% of the time, we'll make it a simple loop, 25% each normal and complex. + if (PRNG.Next(2) == 0) + forStmt.LoopKind = Statements.ForStatement.Kind.SimpleLoop; + else if (PRNG.Next(2) == 0) + forStmt.LoopKind = Statements.ForStatement.Kind.NormalLoop; + else + forStmt.LoopKind = Statements.ForStatement.Kind.ComplexLoop; + + PushScope(forLoopScope); + + forStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); + forStmt.LoopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); + + //TODO-imp: ctrlFlowStack + //TODO future: label + for (int i = 0; i < n; ++i) + { + StmtKind cur; + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + forStmt.AddToBody(StatementHelper(cur, depth + 1)); + } + + PopScope(); // pop for-loop scope + return Annotate(Block(forStmt.Generate(false)), "S:for-loop"); + + } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 4dbb8bf..2266118 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -20,8 +20,9 @@ public class ConfigOptions : OptionsBase // Statement weights public double VariableDeclarationWeight = 0.5; - public double IfElseStatementWeight = 1; - public double AssignStatementWeight = 1; + public double IfElseStatementWeight = 0.4; + public double AssignStatementWeight = 0.5; + public double ForStatementWeight = 1; // Type weights public double BooleanWeight = 1; @@ -85,6 +86,28 @@ public class ConfigOptions : OptionsBase public double EqualsWeight = 1; public double NotEqualsWeight = 1; + // Config options + // Probablity of removing loop parameters -- see comments on BoundParameters in ForStatement + public double LoopParametersRemovalProbability = 0.1; + + // Probability of having forward loop whose induction variable always increases + public double LoopForwardProbability = 0.7; + + //Probabilty whether loop induction variable should start from loop invariant value or +/- 3 + public double LoopStartFromInvariantProbabilty = 0.5; + + //Probabilty whether loop step should happen pre or post break condition + public double LoopStepPreBreakCondProbability = 0.5; + + // Probability of usage of array.length vs. loopinvariant + public double UseLoopInvariantVariableProbability = 1.0; // Always have 1.0 for now to stop making .length as invariant because that could lead to long loops + + // This will put loop condition at the end of the loop body. + // Always use ContinueStatementWeight = 0 if this is true (see lessmath_no_continue.xml), otherwise there is a chance of infinite loop here. + // This is a quick fix for now. We need to come up with a better solution for this for IE11. + public bool AllowLoopCondAtEnd = false; + + public double Lookup(Tree.ValueType type) { string str = Enum.GetName(typeof(Microsoft.CodeAnalysis.SpecialType), type.DataType); diff --git a/Helpers/Constants.cs b/Helpers/Constants.cs new file mode 100644 index 0000000..4fdc2bf --- /dev/null +++ b/Helpers/Constants.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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public static class Constants + { + public static string LoopInvariantName = "loopInvariant"; + } +} diff --git a/Program.cs b/Program.cs index 813e034..2603265 100644 --- a/Program.cs +++ b/Program.cs @@ -6,7 +6,7 @@ class Program { static void Main(string[] args) { - PRNG.Initialize(5); + PRNG.Initialize(-1); int testId = 1; while (true) diff --git a/README.md b/README.md index 418aca0..6965137 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 2. Introduce scopes so variables can be reused. 3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' 4. Added if-else statement -5. Assignment statement, /* S:Assign */ annotation \ No newline at end of file +5. Assignment statement, /* S:Assign */ annotation +6. For-loop \ No newline at end of file diff --git a/Statements/ForStatement.cs b/Statements/ForStatement.cs new file mode 100644 index 0000000..457ccee --- /dev/null +++ b/Statements/ForStatement.cs @@ -0,0 +1,190 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen.Statements +{ + public class ForStatement : LoopStatement + { + public List symTableLog = new List(); + + public ExpressionSyntax LoopStep; + + public Kind LoopKind; + public enum Kind + { + SimpleLoop, + NormalLoop, + ComplexLoop + } + + public ForStatement(TestCase tc) + : base(tc) + { + } + + //public StatementSyntax Generate() + //{ + // RenderPreLoopBody(context, labels); + + // RenderLoopBody(context); + + // RenderPostLoopBody(context, labels); + //} + + public override List Generate(bool labels) + { + //TODO-feature render comments + //base.RenderInternal(context, labels); + + List result = new List(); + + // Induction variables to be initialized outside the loop + VariableDeclarationSyntax initCode = GenerateIVInitCode(false); + if (initCode != null) + { + result.Add(LocalDeclarationStatement(initCode)); + } + //context.BeginLine(GenerateIVInitCode(false)); + //context.WriteLine(";"); + + //if (labels) + //{ + // foreach (string sLbl in Labels) + // { + // context.BeginLine("{0}: ", sLbl); + // context.WriteLine(""); + // } + //} + + // guard condition + ExpressionSyntax condition = GenerateIVLoopGuardCode(); + if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) + { + ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, IdentifierName(LoopVar), Bounds); + if (condition == null) + { + condition = boundCond; + } + else + { + condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, boundCond); + } + } + + // induction variables to be incr/decr + SeparatedSyntaxList incrementors = GenerateIVStepCode(); + if (LoopKind == Kind.NormalLoop) + { + incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, IdentifierName(LoopVar))); + } + else if (LoopKind == Kind.ComplexLoop) + { + incrementors.Add(LoopStep); + } + + // Add step/break condition at the beginning + List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); + + // Add actual loop body + loopBody.AddRange(GetLoopBody()); + + // Add step/break condition at the end + loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); + + ForStatementSyntax forStmt = ForStatement(Block(loopBody)); + + VariableDeclarationSyntax declaration = GenerateIVInitCode(true); + if (declaration != null) + { + forStmt = forStmt.WithDeclaration(declaration); + } + forStmt = forStmt.WithCondition(condition).WithIncrementors(incrementors); + result.Add(forStmt); + return result; + + //return ForStatement( + // declaration: GenerateIVInitCode(true), // induction variables to be initialized inside the loop + // initializers: null, + // condition: condition, + // incrementors: incrementors, + // statement: Block(loopBody) + // ); + + //// Init + //context.BeginLine("for("); + + //// induction variables to be initialized inside the loop + //context.Write(GenerateIVInitCode(true)); + //context.Write(";"); + + //// Cond + //loopCode = GenerateIVLoopGuardCode(); + //context.Write("{0}", loopCode); + + //if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) + //{ + // if (!String.IsNullOrEmpty(loopCode)) + // context.Write(" &&"); + // context.Write(" {0} < (", LoopVar); + // Bounds.Render(context); + // context.Write(")"); + + //} + //context.Write(";"); + + //// induction variables to be incr/decr + //loopCode = GenerateIVStepCode(); + //context.Write("{0}", loopCode); + + //if (LoopKind == Kind.NormalLoop) + //{ + // if (!String.IsNullOrEmpty(loopCode)) + // context.Write(" ,"); + // context.Write(" {0}++", LoopVar); + //} + //else if (LoopKind == Kind.ComplexLoop) + //{ + // if (!String.IsNullOrEmpty(loopCode)) + // context.Write(","); + // context.Write(" "); + // LoopStep.Render(context); + //} + //context.Write(") {{"); + //context.WriteLine(""); + + //context.Depth++; + + //// Add step/break condition at the beginning + //GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false).ForEach(bc => { context.BeginLine(bc); context.WriteLine(""); }); + + } + + + //public override void RenderPostLoopBody(RenderContext context, bool labels) + //{ + // // Add step/break condition at the end + // GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true).ForEach(bc => { context.BeginLine(bc); context.WriteLine(""); }); + + // context.Depth--; + // context.BeginLine("}}"); + // context.WriteLine(""); + + // RenderFunctionWrapperEnd(context); + + // Debug.Assert(HasSuccessfullyGenerated(), "ForStatement didn't generate properly. Please check the loop variables."); + //} + }; +} diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs new file mode 100644 index 0000000..8dc2944 --- /dev/null +++ b/Statements/LoopStatement.cs @@ -0,0 +1,720 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen.Statements +{ + // This struct indicates which parameters of the for loop are removed. + // Note: We only remove __loopvars. In NormalLoops and ComplexLoops, we will still have other + // statements as loop conditions and increments. + public class LoopControlParameters + { + public Operator LoopBreakOperator; + + /// + /// Valid for ForStatement only + /// true - IV is initialized inside loop head. for(init; cond; incr) + /// false - IV is initialized outside loop head. for (; cond; incr) + /// + public bool IsInitInLoopHeader; + + /// + /// true - IV's guard condition is inside loop head. for(init; cond; incr) + /// false - IV's guard condition is outside loop head. for (init; ; incr) or while(expr) { if(cond) break; ...} + /// + public bool IsBreakCondInLoopHeader; + + /// + /// Valid for ForStatement only + /// true - IV's step expression is inside loop head. for(init; cond; incr) + /// false - IV's step expression is outside loop head. for (init; cond; ) { incr; ...} + /// + public bool IsStepInLoopHeader; + + /// + /// true - IV's break condition is at the end of loop body + /// false - IV's break condition is at the beginning of loop body + /// + public bool IsBreakCondAtEndOfLoopBody; + + /// + /// true - IV is incremented pre break condition e.g. ... incr; if(cond) break; + /// false - IV is incremented post break condition e.g. ... if(cond) break; incr; + /// + public bool IsStepBeforeBreakCondition; + + /// + /// true - loop step increases IV in step expression. i++ + /// false - loop step decreases IV in step expression. i-- + /// + public bool IsForwardLoop; + + /// + /// Determines loop change factor.if 5 then IV += 5; + /// + public int LoopInductionChangeFactor; + + /// + /// true - loopInvariant is used for loopStart and loopEnd + /// false - array.length is used for loopStart and loopEnd + /// + public bool IsLoopInvariantVariableUsed; + + /// + /// true - Initialize IV = loopInvariant + /// false - Initialize IV = loopInvariant +/- 3 + /// + public bool IsLoopStartFromInvariant; + + /// + /// Variation to initialized value of loopvar. + /// e.g.g If this is ForwardLoop, ChangeFactor=3 and break condition is 12, then there are 3 possible initialization values for loopvar: + /// 3,6,9 + /// 4,7,10 + /// 5,8,11 + /// + public int LoopInitValueVariation; + } + + public class InductionVariable + { + private static int NumOfIterations = 3; + public bool IsPrimary; + public string Name; + public LoopControlParameters LoopParameters; + + public bool isLoopInitGenerated = false; + public bool isLoopStepGenerated = false; + public bool isLoopBreakGenerated = false; + public string LoopInvariantName = null; + + // Variables used in ToString() method + private int __loopStart = -1; + private int __loopEnd = -1; + + + #region Methods + + //public override string ToString() + //{ + // if (__loopStart == -1) GetLoopStart(); + // if (__loopEnd == -1) GetLoopEnd(); + + // if (IsPrimary) + // { + // if (LoopParameters.IsStepBeforeBreakCondition) + // return String.Format("({0} = {1} ; {4}, {0} {2} {3}; )", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + // else + // return String.Format("({0} = {1} ; {0} {2} {3}; {4})", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + // } + // else + // { + // return String.Format("({0} = {1} ; ; {2})", Name, __loopStart, GetLoopStep()); + // } + //} + + /// + /// Returns if this induction variable had generated code for init, step and guard check. + /// + /// + public bool HasSuccessfullyGenerated() + { + if (IsPrimary) + { + return isLoopInitGenerated && isLoopStepGenerated && isLoopBreakGenerated; + } + else + { + return isLoopInitGenerated && isLoopStepGenerated; + } + } + + /// + /// Returns value of loopinduction variable with which it should start the loop + /// + /// + internal ExpressionSyntax GetLoopStart() + { + __loopStart = 0; + // If loop starts with invariant then _loopvar = loopInvariant; + if (LoopParameters.IsLoopStartFromInvariant) + return IdentifierName(LoopInvariantName); + + int loopStartValue = (InductionVariable.NumOfIterations * LoopParameters.LoopInductionChangeFactor); + + if (LoopParameters.IsForwardLoop) + loopStartValue += LoopParameters.LoopInitValueVariation; + else + loopStartValue -= LoopParameters.LoopInitValueVariation; + + __loopStart = (LoopParameters.IsForwardLoop ? -1 : 1) * loopStartValue; + + return BinaryExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.SubtractExpression : SyntaxKind.AddExpression, + IdentifierName(LoopInvariantName), + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(loopStartValue))); + //return String.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "-" : "+", loopStartValue.ToString()); + } + + /// + /// Returns value of loopinduction variable with which it should end the loop + /// + /// + internal ExpressionSyntax GetLoopEnd() + { + int numOfIterations = InductionVariable.NumOfIterations; + __loopEnd = 0; + // If loop doesn't start with invariant, it ends with loopInvariant : __loopvar = loopInvariant - N; __loopvar < loopInvariant; + if (!LoopParameters.IsLoopStartFromInvariant) + numOfIterations = 0; + + // If we are incr/decr before break condition, we should compente with increasing the break bounds + if (LoopParameters.IsStepBeforeBreakCondition) + numOfIterations++; + + // If we have check with <= , we will loop numOfIterations + 1 times, so reduce the numOfIterations by 1 + if (LoopParameters.LoopBreakOperator.Equals(">=")) + numOfIterations--; + + int loopEndValue = numOfIterations * LoopParameters.LoopInductionChangeFactor; + __loopEnd = (LoopParameters.IsForwardLoop ? 1 : -1) * loopEndValue; + + if (loopEndValue == 0) + return IdentifierName(LoopInvariantName); + else + return BinaryExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.AddExpression : SyntaxKind.SubtractExpression, + IdentifierName(LoopInvariantName), + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(loopEndValue))); + //return String.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "+" : "-", loopEndValue.ToString()); + } + + /// + /// Returns the loop step code for this induction variable. Since this can be used in places other + /// than loop control statements, call this only for secondary induction variables. + /// + /// + internal ExpressionSyntax GetLoopStepForSecondaryIV() + { + Debug.Assert(!IsPrimary, "Try to get loop step for primary induction variable."); + int selectedChangeFactor = GetRandomInductionChangeFactor(); + if (selectedChangeFactor == 1) + { + return PostfixUnaryExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.PostIncrementExpression : SyntaxKind.PostDecrementExpression, + IdentifierName(Name)); + //return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; + } + else + { + return AssignmentExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.AddAssignmentExpression : SyntaxKind.SubtractAssignmentExpression, + IdentifierName(Name), + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(selectedChangeFactor))); + //return String.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", selectedChangeFactor); + } + } + + private int GetRandomInductionChangeFactor() + { + if (PRNG.Decide(0.05)) + return 0; + if (LoopParameters.LoopInductionChangeFactor == 1) + return 1; + else + return PRNG.Next(1, LoopParameters.LoopInductionChangeFactor); + } + + /// + /// Returns the step code for given induction variable + /// + /// + /// + internal ExpressionSyntax GetLoopStep() + { + if (LoopParameters.LoopInductionChangeFactor == 1) + { + return PostfixUnaryExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.PostIncrementExpression : SyntaxKind.PostDecrementExpression, + IdentifierName(Name)); + //return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; + } + else + { + return AssignmentExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.AddAssignmentExpression : SyntaxKind.SubtractAssignmentExpression, + IdentifierName(Name), + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(LoopParameters.LoopInductionChangeFactor))); + //return String.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", LoopParameters.LoopInductionChangeFactor); + } + } + + + /// + /// Returns the loop IV access code +/- change factor + /// + /// + internal ExpressionSyntax GetLoopIVAccess() + { + // 5% of time generate '0' for change factor + return BinaryExpression( + LoopParameters.IsForwardLoop ? SyntaxKind.AddExpression : SyntaxKind.SubtractExpression, + IdentifierName(Name), + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(GetRandomInductionChangeFactor()))); + + //return String.Format("{0} {1} {2}", Name, LoopParameters.IsForwardLoop ? "+" : "-", GetRandomInductionChangeFactor()); + } + + /// + /// Returns the guard condition for the loop. Loop will execute as long as this condition is true. + /// + /// + internal ExpressionSyntax GetLoopGuardCondition() + { + return BinaryExpression(getLoopControlOperator(true).Oper, IdentifierName(Name), GetLoopEnd()); + //return String.Format("({0} {1} {2})", Name, getLoopControlOperator(true), GetLoopEnd()); + } + + /// + /// Returns the break condition for the loop. Loop will terminate when this condition is true. + /// + /// + internal ExpressionSyntax GetLoopBreakCondition() + { + return BinaryExpression(getLoopControlOperator(false).Oper, IdentifierName(Name), GetLoopEnd()); + //return String.Format("({0} {1} {2})", Name, getLoopControlOperator(false), GetLoopEnd()); + } + + /// + /// Get the operator required to control the loop based on direction of the loop and guard/break condition + /// + /// + /// + private Operator getLoopControlOperator(bool isFetchingForGuardCondition) + { + Operator result = LoopParameters.LoopBreakOperator; + + // If break operator is '==' then guard operator is '!='. This is same regardless this is forward/backward loop + if (result.Oper == SyntaxKind.EqualsExpression && isFetchingForGuardCondition) + result = Operator.ForSyntaxKind(SyntaxKind.NotEqualsExpression); // "!="; + + // If this is forward loop and we are fetching for break condition, no need to flip the operator + else if (LoopParameters.IsForwardLoop && !isFetchingForGuardCondition) { } + + // If this is reverse loop and we are fetching for guard condition, no need to flop the operator + else if (!LoopParameters.IsForwardLoop && isFetchingForGuardCondition) { } + + // If this is reverse loop and we are fetching for break condition OR this is forward loop and we are fetching for guard condition, + // then flip the operator + else + result = flipOperator(result); + + return result; + } + + private Operator flipOperator(Operator oldOperator) + { + Operator newOperator; + switch (oldOperator.Oper) + { + case SyntaxKind.GreaterThanExpression: // ">": + newOperator = Operator.ForSyntaxKind(SyntaxKind.LessThanExpression); // "<"; + break; + case SyntaxKind.LessThanExpression: // "<": + newOperator = Operator.ForSyntaxKind(SyntaxKind.GreaterThanExpression); // ">"; + break; + case SyntaxKind.GreaterThanOrEqualExpression: // ">=": + newOperator = Operator.ForSyntaxKind(SyntaxKind.LessThanOrEqualExpression); // "<="; + break; + case SyntaxKind.LessThanOrEqualExpression: // "<=": + newOperator = Operator.ForSyntaxKind(SyntaxKind.GreaterThanOrEqualExpression); // ">="; + break; + default: + newOperator = oldOperator; + break; + } + return newOperator; + } + + #endregion + } + + public class LoopStatement + { + private int _nestNum; + private int _noOfSecondaryInductionVariables; + private List _inductionVariables; + + #region Properties + + public ExpressionSyntax Bounds; + + public bool IsContinueAllowedInLoopBody + { + get + { + // If all the primary IV has break condition at the end, then continue is not allowed in the loop body as + // that might cause infinite loop + return !PrimaryInductionVariables.All(iv => iv.LoopParameters.IsBreakCondAtEndOfLoopBody); + } + } + public bool IsWrappedInFunction = false; + public bool IsUseEvalIsWrappedInFunction = false; + public bool IsSnippetGenerated = false; + protected List Body = new List(); + //TODO-future: labels for goto + //public List Labels = new List(); + public List InductionVariables + { + get + { + if (_inductionVariables == null) + _inductionVariables = new List(); + return _inductionVariables; + } + private set { _inductionVariables = value; } + } + + /// + /// Returns list of primary induction variables + /// + public List PrimaryInductionVariables + { + get + { + if (InductionVariables != null) + { + return InductionVariables.Where(iv => iv.IsPrimary).ToList(); + } + else + { + return new List(); + } + } + } + + /// + /// Returns list of secondary induction variables + /// + public List SecondaryInductionVariables + { + get + { + if (InductionVariables != null) + { + return InductionVariables.Where(iv => !iv.IsPrimary).ToList(); + } + else + { + return new List(); + } + } + } + + protected List InductionVariableNamesInitializedOutsideLoop + { + get + { + if (InductionVariables != null) + { + return InductionVariables.Where(iv => !iv.LoopParameters.IsInitInLoopHeader).Select(iv => iv.Name).ToList(); + } + else + { + return new List(); + } + } + } + + protected bool offlineReduceOnly = false; + public string LoopVar; + public int NestNum + { + get { return _nestNum; } + set + { + _nestNum = value; + Debug.Assert(_nestNum > -1, "Trying to set implicit loop var before setting NestNum."); + + // If this is getting reset, clear the previously defined induction variables + if (_inductionVariables != null) + _inductionVariables.Clear(); + + InductionVariables.Add(new Statements.InductionVariable() + { + Name = "__loopvar" + _nestNum, + LoopParameters = TC.AstUtils.GetForBoundParameters(), + IsPrimary = true + }); + ValidateInductionVariablesParams(); + } + } + public Scope LocalScope; + public int NumOfSecondaryInductionVariables + { + get { return _noOfSecondaryInductionVariables; } + set + { + _noOfSecondaryInductionVariables = value; + for (int i = 0; i < _noOfSecondaryInductionVariables; i++) + { + InductionVariables.Add(new Statements.InductionVariable() + { + Name = "__loopSecondaryVar" + _nestNum + "_" + i, + LoopParameters = TC.AstUtils.GetForBoundParameters(), + IsPrimary = PRNG.Decide(0.1) // Have 10% of extra primary induction variables + }); + } + ValidateInductionVariablesParams(); + } + } + public TestCase TC; + + /// + /// Validates the loop parameters set for list of induction variables + /// + private void ValidateInductionVariablesParams() + { + for (int i = 0; i < InductionVariables.Count; i++) + { + var inductionVariable = InductionVariables[i]; + bool isForStatement = typeof(ForStatement) == this.GetType(); + + // We generate loop header init/step only for ForStatement. So set these to 'false' for everything other than ForStatement + inductionVariable.LoopParameters.IsInitInLoopHeader = isForStatement && inductionVariable.LoopParameters.IsInitInLoopHeader; + inductionVariable.LoopParameters.IsStepInLoopHeader = isForStatement && inductionVariable.LoopParameters.IsStepInLoopHeader; + + //TODO-future: arrays + //if (!inductionVariable.LoopParameters.IsLoopInvariantVariableUsed) + //{ + // string arrayVariableToAccessForLength = LocalScope.GetRandomArrayObject(SymbolAction.Read); + // if (!String.IsNullOrEmpty(arrayVariableToAccessForLength)) + // { + // inductionVariable.LoopInvariantName = String.Format("{0}.length", arrayVariableToAccessForLength); + // } + //} + + if (String.IsNullOrEmpty(inductionVariable.LoopInvariantName)) + inductionVariable.LoopInvariantName = Constants.LoopInvariantName; + } + } + + protected bool HasSuccessfullyGenerated() + { + var result = true; + // Check if IV has generated successfully + foreach (var inductionVariable in InductionVariables) + { + result &= inductionVariable.HasSuccessfullyGenerated(); + } + return result; + } + #endregion + + public void AddToBody(StatementSyntax stmt) + { + Body.Add(stmt); + } + + public LoopStatement(TestCase tc) + { + TC = tc; + //LocalScope = new Scope(TC, ScopeKind.loopScope, tc); + } + + public string GetImplicitLoopVar() + { + return "__loopvar" + NestNum; + } + + //public virtual StatementSyntax GeneratePreLoopBody(bool labels) + //{ + // return null; + //} + + public virtual List Generate(bool labels) + { + return null; + } + + protected List GetLoopBody() + { + // load the value of Property once instead of reading from Property everytime because it queries the list of IVs + bool isContinueAllowedInLoopBody = IsContinueAllowedInLoopBody; + +#if DEBUG + foreach (StatementSyntax sm in Body) + { + if (sm is ContinueStatementSyntax) + { + Debug.Assert(isContinueAllowedInLoopBody, "continue is not allowed in loop since break condition is at the end of loop."); + } + } +#endif + return Body; + } + + //public virtual StatementSyntax GeneratePostLoopBody(bool labels) + //{ + // return null; + //} + + #region Loop induction code generation + + private List generateComments() + { + return InductionVariables.Select(iv => iv.ToString()).ToList(); + } + + protected VariableDeclarationSyntax GenerateIVInitCode(bool isInitLoopHead = false) + { + List loopInits = new List(); + + // Induction variables to be initialized outside the loop + foreach (var inductionVar in InductionVariables) + { + if (this.GetType() != typeof(ForStatement) || // ForStatement may have init code in loop head. For other loops it has to be outside loop + inductionVar.LoopParameters.IsInitInLoopHeader == isInitLoopHead) + { + inductionVar.isLoopInitGenerated = true; + loopInits.Add(VariableDeclarator(Identifier(inductionVar.Name)).WithInitializer(EqualsValueClause(inductionVar.GetLoopStart()))); + //loopInits.Add(String.Format("{0} = {1}", inductionVar.Name, inductionVar.GetLoopStart())); + } + } + if (loopInits.Count > 0) + { + return VariableDeclaration(Helpers.GetToken(SyntaxKind.IntKeyword), SeparatedList(loopInits)); + //return "var " + String.Join(",", loopInits); + } + return null; + } + + protected SeparatedSyntaxList GenerateIVStepCode() + { + // Induction variables to be incr/decr in loop body + List loopInits = new List(); + List finalInits = new List(); + + for (int i = 0; i < InductionVariables.Count; i++) + { + InductionVariable inductionVariable = InductionVariables[i]; + if (inductionVariable.LoopParameters.IsStepInLoopHeader) + { + inductionVariable.isLoopStepGenerated = true; + //loopInits.Add(Token(SyntaxKind.CommaToken)); + loopInits.Add(inductionVariable.GetLoopStep()); + //loopInits.Add(String.Format("{0}", inductionVar.GetLoopStep())); + } + } + + if (loopInits.Count > 0) + { + finalInits.Add(loopInits[0]); + for (int i = 1; i < loopInits.Count; i++) + { + finalInits.Add(Token(SyntaxKind.CommaToken)); + finalInits.Add(loopInits[i]); + } + } + + return SeparatedList(finalInits); + //return String.Join(", ", loopInits); + } + + protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCondAtTheEnd) + { + List loopBreaks = new List(); + List loopPreCondSteps = new List(); + List loopPostCondSteps = new List(); + + // Generate break and step condition for primary variables + foreach (var inductionVar in PrimaryInductionVariables) + { + + if (!inductionVar.LoopParameters.IsBreakCondInLoopHeader && // the break condition is not in loop header + inductionVar.LoopParameters.IsBreakCondAtEndOfLoopBody == isCodeForBreakCondAtTheEnd) // If decided to add step at end of loop body and this is end of loop body + { + inductionVar.isLoopBreakGenerated = true; + loopBreaks.Add(IfStatement(inductionVar.GetLoopBreakCondition(), Block(BreakStatement()))); + //loopBreaks.Add(String.Format("if {0} break;", inductionVar.GetLoopBreakCondition())); + } + } + + // Generate step condition for secondary variables + foreach (var inductionVar in InductionVariables) + { + // Add step condition if step is not in loop header + if (!inductionVar.LoopParameters.IsStepInLoopHeader && // the step condition is not in loop header + inductionVar.LoopParameters.IsBreakCondAtEndOfLoopBody == isCodeForBreakCondAtTheEnd) // If decided to add step at end of loop body and this is end of loop body + { + inductionVar.isLoopStepGenerated = true; + if (inductionVar.LoopParameters.IsStepBeforeBreakCondition) + { + loopPreCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); + //loopPreCondSteps.Add(String.Format("{0};", inductionVar.GetLoopStep())); + } + else + { + loopPostCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); + //loopPostCondSteps.Add(String.Format("{0};", inductionVar.GetLoopStep())); + } + } + } + loopBreaks.InsertRange(0, loopPreCondSteps); + loopBreaks.AddRange(loopPostCondSteps); + return loopBreaks; + } + + protected ExpressionSyntax GenerateIVLoopGuardCode() + { + List loopInits = new List(); + //InductionVariable inductionVariable = PrimaryInductionVariables[0]; + ExpressionSyntax guardCondition = null; + + //// Only generate guard condition for primary induction variables and whose LoopHeadCondition = true + //if (inductionVariable.LoopParameters.IsBreakCondInLoopHeader) + //{ + // inductionVariable.isLoopBreakGenerated = true; + // loopInits.Add(inductionVariable.GetLoopGuardCondition()); + //} + + // Secondary induction variables to be incr/decr in loop body + foreach (var inductionVariable in PrimaryInductionVariables) + { + // Only generate guard condition for primary induction variables and whose LoopHeadCondition = true + if (inductionVariable.LoopParameters.IsBreakCondInLoopHeader) + { + inductionVariable.isLoopBreakGenerated = true; + var currCondition = inductionVariable.GetLoopGuardCondition(); + if (guardCondition != null) + { + guardCondition = BinaryExpression(SyntaxKind.LogicalAndExpression, guardCondition, currCondition); + } + else + { + guardCondition = currCondition; + } + + //loopInits.Add(inductionVariable.GetLoopGuardCondition()); + } + } + return guardCondition; + //return String.Join("&&", loopInits); + } + + #endregion + + } +} diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index d8a2076..4ca86ac 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Antigen.Statements; namespace Antigen.Tree { @@ -205,6 +206,46 @@ where z.Data.HasFlag(OpFlags.String) // Do a weighted random choice. return PRNG.WeightedChoice(ops); } + + internal LoopControlParameters GetForBoundParameters() + { + LoopControlParameters Ret = new LoopControlParameters(); + + Ret.IsInitInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); + Ret.IsStepInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); + Ret.IsBreakCondInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); + + Ret.IsLoopInvariantVariableUsed = PRNG.Decide(Options.UseLoopInvariantVariableProbability); + Ret.IsBreakCondAtEndOfLoopBody = Options.AllowLoopCondAtEnd ? PRNG.Decide(0.5) : false; + Ret.IsForwardLoop = PRNG.Decide(Options.LoopForwardProbability); + Ret.IsLoopStartFromInvariant = PRNG.Decide(Options.LoopStartFromInvariantProbabilty); + Ret.LoopInductionChangeFactor = PRNG.Next(1, 5); + Ret.LoopInitValueVariation = PRNG.Next(0, Ret.LoopInductionChangeFactor); + Ret.IsStepBeforeBreakCondition = PRNG.Decide(Options.LoopStepPreBreakCondProbability); + + // Generate operator for break condition in a forward loop + // Depending on the loop type/condition, we will later flip the operator in LoopStatement + int operatorChoice = PRNG.Next(5); + switch (operatorChoice) + { + case 0: + case 1: + Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanExpression); + break; + case 2: + case 3: + Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanOrEqualExpression); + break; + case 4: + Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.EqualsExpression); + // variation doesn't guarantee rounding which is needed with == operator. So make invariant as 0. + // eg. ChangeFactor = 2, __loopvar = 3; __loopvar != (3 * 2); __loopvar += 2; We will break in 3 iterations without invariation + // eg. ChangeFactor = 2, __loopvar = 3 + 1; __loopvar != (3 * 2); __loopvar += 2; We will go to infinite loop because condition is never true + Ret.LoopInitValueVariation = 0; + break; + } + return Ret; + } #endregion } diff --git a/Tree/Operators.cs b/Tree/Operators.cs index 46e7ece..605f088 100644 --- a/Tree/Operators.cs +++ b/Tree/Operators.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis.CSharp; using System.Collections.Generic; +using System.Linq; namespace Antigen.Tree { @@ -107,6 +108,11 @@ public static List GetOperators() return operators; } + public static Operator ForSyntaxKind(SyntaxKind operKind) + { + return operators.First(o => o.Oper == operKind); + } + public override string ToString() { return renderText; diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 0123467..bd5236c 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -5,6 +5,7 @@ public enum StmtKind VariableDeclaration, IfElseStatement, AssignStatement, + ForStatement, } //public class Statements From 120098cda4398ac5a03e47049e7742251b7b16ee Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 27 Dec 2020 00:24:11 -0800 Subject: [PATCH 010/149] do { .. } while (...) --- .gitignore | 1 + BaseMethod.cs | 33 +++++++++++++++++++++ Config/ConfigOptions.cs | 3 +- README.md | 3 +- Statements/DoWhileStatement.cs | 52 ++++++++++++++++++++++++++++++++++ Tree/Statements.cs | 1 + 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 Statements/DoWhileStatement.cs diff --git a/.gitignore b/.gitignore index 854dc0f..730a7a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bin obj .vs +*.g.cs **\*.g.cs \ No newline at end of file diff --git a/BaseMethod.cs b/BaseMethod.cs index f4c693e..7a1e3cf 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -205,6 +205,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) forStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); forStmt.LoopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); + //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label for (int i = 0; i < n; ++i) @@ -224,7 +225,39 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop for-loop scope return Annotate(Block(forStmt.Generate(false)), "S:for-loop"); + } + case StmtKind.DoWhileStatement: + { + Scope doWhileScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); + DoWhileStatement doStmt = new DoWhileStatement(testCase); + //TODO:config + int n = 3; // max statements + doStmt.NestNum = depth; + doStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + + PushScope(doWhileScope); + + doStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + + //TODO-imp: AddInductionVariables + //TODO-imp: ctrlFlowStack + //TODO future: label + for (int i = 0; i < n; ++i) + { + StmtKind cur; + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + doStmt.AddToBody(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop do-while scope + return Annotate(Block(doStmt.Generate(false)), "S:do-while"); } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 2266118..0635024 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -22,7 +22,8 @@ public class ConfigOptions : OptionsBase public double VariableDeclarationWeight = 0.5; public double IfElseStatementWeight = 0.4; public double AssignStatementWeight = 0.5; - public double ForStatementWeight = 1; + public double ForStatementWeight = 0.5; + public double DoWhileStatementWeight = 0.5; // Type weights public double BooleanWeight = 1; diff --git a/README.md b/README.md index 6965137..7b65648 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' 4. Added if-else statement 5. Assignment statement, /* S:Assign */ annotation -6. For-loop \ No newline at end of file +6. For-loop +7. Do-While loop \ No newline at end of file diff --git a/Statements/DoWhileStatement.cs b/Statements/DoWhileStatement.cs new file mode 100644 index 0000000..c395d97 --- /dev/null +++ b/Statements/DoWhileStatement.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen.Statements +{ + public class DoWhileStatement : LoopStatement + { + public DoWhileStatement(TestCase tc) : base(tc) + { + } + + public override List Generate(bool labels) + { + List result = new List(); + + VariableDeclarationSyntax initCode = GenerateIVInitCode(false); + if (initCode != null) + { + result.Add(LocalDeclarationStatement(initCode)); + } + + // Add step/break condition at the beginning + List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); + + // Add actual loop body + loopBody.AddRange(GetLoopBody()); + + // Add step/break condition at the end + loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); + + // guard condition + ExpressionSyntax condition = GenerateIVLoopGuardCode(); + if (condition == null) + { + condition = Bounds; + } + else + { + condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, Bounds); + } + result.Add(DoStatement(Block(loopBody), condition)); + return result; + } + } +} diff --git a/Tree/Statements.cs b/Tree/Statements.cs index bd5236c..6867d32 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -6,6 +6,7 @@ public enum StmtKind IfElseStatement, AssignStatement, ForStatement, + DoWhileStatement, } //public class Statements From 7afd12c67c8c736c7b5b4935dcee60f6fb415f97 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 27 Dec 2020 00:42:31 -0800 Subject: [PATCH 011/149] /* S#xyz: stmt */ --- BaseMethod.cs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/BaseMethod.cs b/BaseMethod.cs index 7a1e3cf..446a3fe 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -16,6 +16,8 @@ public class BaseMethod private string Name; #if DEBUG private bool annotateComments = true; + private Dictionary expressionsCount = new Dictionary(); + private Dictionary statementsCount = new Dictionary(); #else private bool annotateComments = false; #endif @@ -121,7 +123,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); - return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "S:VarDecl"); + return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "VarDecl"); } case StmtKind.IfElseStatement: { @@ -172,7 +174,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop 'else' body scope - return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "S:IfElse"); + return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "IfElse"); } case StmtKind.AssignStatement: { @@ -180,7 +182,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Tree.ValueType variableType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, variableType, depth); ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, depth); - return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "S:Assign"); + return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); } case StmtKind.ForStatement: { @@ -224,7 +226,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop for-loop scope - return Annotate(Block(forStmt.Generate(false)), "S:for-loop"); + return Annotate(Block(forStmt.Generate(false)), "for-loop"); } case StmtKind.DoWhileStatement: { @@ -257,7 +259,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop do-while scope - return Annotate(Block(doStmt.Generate(false)), "S:do-while"); + return Annotate(Block(doStmt.Generate(false)), "do-while"); } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -271,10 +273,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i switch (exprKind) { case ExprKind.LiteralExpression: - return Annotate(Helpers.GetLiteralExpression(exprType), "E:Literal"); + return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); case ExprKind.VariableExpression: - return Annotate(IdentifierName(CurrentScope.GetRandomVariable(exprType)), "E:Var"); + return Annotate(IdentifierName(CurrentScope.GetRandomVariable(exprType)), "Var"); case ExprKind.BinaryOpExpression: Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); @@ -298,7 +300,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i lhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType), lhsExprType, depth + 1); rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth + 1); } - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "E:BinOp"); + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); default: Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); @@ -313,7 +315,14 @@ private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) { return expression; } - return expression.WithTrailingTrivia(TriviaList(Comment("/* " + comment + " */"))); + + string typeName = expression.GetType().Name; + if (!expressionsCount.ContainsKey(typeName)) + { + expressionsCount[typeName] = 0; + } + expressionsCount[typeName]++; + return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{expressionsCount[typeName]}: {comment} */"))); } private StatementSyntax Annotate(StatementSyntax statement, string comment) @@ -322,7 +331,13 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment) { return statement; } - return statement.WithTrailingTrivia(TriviaList(Comment("/* " + comment + " */"))); + string typeName = statement.GetType().Name; + if (!statementsCount.ContainsKey(typeName)) + { + statementsCount[typeName] = 0; + } + statementsCount[typeName]++; + return statement.WithTrailingTrivia(TriviaList(Comment($"/* S#{statementsCount[typeName]}: {comment} */"))); } } } From dcc489834c007260333d813b14a496cbf19d899c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 27 Dec 2020 01:09:23 -0800 Subject: [PATCH 012/149] while (...) { .. } --- BaseMethod.cs | 33 +++++++++++ Config/ConfigOptions.cs | 3 +- README.md | 3 +- Statements/DoWhileStatement.cs | 7 ++- Statements/ForStatement.cs | 105 ++------------------------------- Statements/LoopStatement.cs | 65 ++++++-------------- Statements/WhileStatement.cs | 56 ++++++++++++++++++ Tree/Statements.cs | 1 + 8 files changed, 120 insertions(+), 153 deletions(-) create mode 100644 Statements/WhileStatement.cs diff --git a/BaseMethod.cs b/BaseMethod.cs index 446a3fe..67ec8b4 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -261,6 +261,39 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop do-while scope return Annotate(Block(doStmt.Generate(false)), "do-while"); } + case StmtKind.WhileStatement: + { + Scope whileScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); + WhileStatement whileStmt = new WhileStatement(testCase); + //TODO:config + int n = 3; // max statements + whileStmt.NestNum = depth; + whileStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + + PushScope(whileScope); + + whileStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + + //TODO-imp: AddInductionVariables + //TODO-imp: ctrlFlowStack + //TODO future: label + for (int i = 0; i < n; ++i) + { + StmtKind cur; + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + whileStmt.AddToBody(StatementHelper(cur, depth + 1)); + } + + PopScope(); // pop while scope + return Annotate(Block(whileStmt.Generate(false)), "while-loop"); + } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 0635024..126d90b 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -23,7 +23,8 @@ public class ConfigOptions : OptionsBase public double IfElseStatementWeight = 0.4; public double AssignStatementWeight = 0.5; public double ForStatementWeight = 0.5; - public double DoWhileStatementWeight = 0.5; + public double DoWhileStatementWeight = 0.2; + public double WhileStatementWeight = 0.5; // Type weights public double BooleanWeight = 1; diff --git a/README.md b/README.md index 7b65648..e93a7e7 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 4. Added if-else statement 5. Assignment statement, /* S:Assign */ annotation 6. For-loop -7. Do-While loop \ No newline at end of file +7. Do-While loop +8. While loop \ No newline at end of file diff --git a/Statements/DoWhileStatement.cs b/Statements/DoWhileStatement.cs index c395d97..64b603d 100644 --- a/Statements/DoWhileStatement.cs +++ b/Statements/DoWhileStatement.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -12,9 +13,7 @@ namespace Antigen.Statements { public class DoWhileStatement : LoopStatement { - public DoWhileStatement(TestCase tc) : base(tc) - { - } + public DoWhileStatement(TestCase tc) : base(tc) {} public override List Generate(bool labels) { @@ -46,6 +45,8 @@ public override List Generate(bool labels) condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, Bounds); } result.Add(DoStatement(Block(loopBody), condition)); + Debug.Assert(HasSuccessfullyGenerated(), "DoWhileStatement didn't generate properly. Please check the loop variables."); + return result; } } diff --git a/Statements/ForStatement.cs b/Statements/ForStatement.cs index 457ccee..c735777 100644 --- a/Statements/ForStatement.cs +++ b/Statements/ForStatement.cs @@ -30,25 +30,10 @@ public enum Kind ComplexLoop } - public ForStatement(TestCase tc) - : base(tc) - { - } - - //public StatementSyntax Generate() - //{ - // RenderPreLoopBody(context, labels); - - // RenderLoopBody(context); - - // RenderPostLoopBody(context, labels); - //} + public ForStatement(TestCase tc) : base(tc) {} public override List Generate(bool labels) { - //TODO-feature render comments - //base.RenderInternal(context, labels); - List result = new List(); // Induction variables to be initialized outside the loop @@ -57,23 +42,12 @@ public override List Generate(bool labels) { result.Add(LocalDeclarationStatement(initCode)); } - //context.BeginLine(GenerateIVInitCode(false)); - //context.WriteLine(";"); - - //if (labels) - //{ - // foreach (string sLbl in Labels) - // { - // context.BeginLine("{0}: ", sLbl); - // context.WriteLine(""); - // } - //} // guard condition ExpressionSyntax condition = GenerateIVLoopGuardCode(); if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) { - ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, IdentifierName(LoopVar), Bounds); + ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, Helpers.GetVariableAccessExpression(LoopVar), Bounds); if (condition == null) { condition = boundCond; @@ -88,7 +62,7 @@ public override List Generate(bool labels) SeparatedSyntaxList incrementors = GenerateIVStepCode(); if (LoopKind == Kind.NormalLoop) { - incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, IdentifierName(LoopVar))); + incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, Helpers.GetVariableAccessExpression(LoopVar))); } else if (LoopKind == Kind.ComplexLoop) { @@ -113,78 +87,9 @@ public override List Generate(bool labels) } forStmt = forStmt.WithCondition(condition).WithIncrementors(incrementors); result.Add(forStmt); - return result; - - //return ForStatement( - // declaration: GenerateIVInitCode(true), // induction variables to be initialized inside the loop - // initializers: null, - // condition: condition, - // incrementors: incrementors, - // statement: Block(loopBody) - // ); - - //// Init - //context.BeginLine("for("); - - //// induction variables to be initialized inside the loop - //context.Write(GenerateIVInitCode(true)); - //context.Write(";"); - - //// Cond - //loopCode = GenerateIVLoopGuardCode(); - //context.Write("{0}", loopCode); - - //if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) - //{ - // if (!String.IsNullOrEmpty(loopCode)) - // context.Write(" &&"); - // context.Write(" {0} < (", LoopVar); - // Bounds.Render(context); - // context.Write(")"); - - //} - //context.Write(";"); - - //// induction variables to be incr/decr - //loopCode = GenerateIVStepCode(); - //context.Write("{0}", loopCode); - - //if (LoopKind == Kind.NormalLoop) - //{ - // if (!String.IsNullOrEmpty(loopCode)) - // context.Write(" ,"); - // context.Write(" {0}++", LoopVar); - //} - //else if (LoopKind == Kind.ComplexLoop) - //{ - // if (!String.IsNullOrEmpty(loopCode)) - // context.Write(","); - // context.Write(" "); - // LoopStep.Render(context); - //} - //context.Write(") {{"); - //context.WriteLine(""); - - //context.Depth++; - - //// Add step/break condition at the beginning - //GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false).ForEach(bc => { context.BeginLine(bc); context.WriteLine(""); }); + Debug.Assert(HasSuccessfullyGenerated(), "ForStatement didn't generate properly. Please check the loop variables."); + return result; } - - - //public override void RenderPostLoopBody(RenderContext context, bool labels) - //{ - // // Add step/break condition at the end - // GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true).ForEach(bc => { context.BeginLine(bc); context.WriteLine(""); }); - - // context.Depth--; - // context.BeginLine("}}"); - // context.WriteLine(""); - - // RenderFunctionWrapperEnd(context); - - // Debug.Assert(HasSuccessfullyGenerated(), "ForStatement didn't generate properly. Please check the loop variables."); - //} }; } diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 8dc2944..18921b8 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -107,23 +107,23 @@ public class InductionVariable #region Methods - //public override string ToString() - //{ - // if (__loopStart == -1) GetLoopStart(); - // if (__loopEnd == -1) GetLoopEnd(); - - // if (IsPrimary) - // { - // if (LoopParameters.IsStepBeforeBreakCondition) - // return String.Format("({0} = {1} ; {4}, {0} {2} {3}; )", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); - // else - // return String.Format("({0} = {1} ; {0} {2} {3}; {4})", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); - // } - // else - // { - // return String.Format("({0} = {1} ; ; {2})", Name, __loopStart, GetLoopStep()); - // } - //} + public override string ToString() + { + if (__loopStart == -1) GetLoopStart(); + if (__loopEnd == -1) GetLoopEnd(); + + if (IsPrimary) + { + if (LoopParameters.IsStepBeforeBreakCondition) + return String.Format("({0} = {1} ; {4}, {0} {2} {3}; )", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + else + return String.Format("({0} = {1} ; {0} {2} {3}; {4})", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + } + else + { + return String.Format("({0} = {1} ; ; {2})", Name, __loopStart, GetLoopStep()); + } + } /// /// Returns if this induction variable had generated code for init, step and guard check. @@ -531,7 +531,6 @@ public void AddToBody(StatementSyntax stmt) public LoopStatement(TestCase tc) { TC = tc; - //LocalScope = new Scope(TC, ScopeKind.loopScope, tc); } public string GetImplicitLoopVar() @@ -539,11 +538,6 @@ public string GetImplicitLoopVar() return "__loopvar" + NestNum; } - //public virtual StatementSyntax GeneratePreLoopBody(bool labels) - //{ - // return null; - //} - public virtual List Generate(bool labels) { return null; @@ -566,11 +560,6 @@ protected List GetLoopBody() return Body; } - //public virtual StatementSyntax GeneratePostLoopBody(bool labels) - //{ - // return null; - //} - #region Loop induction code generation private List generateComments() @@ -590,13 +579,11 @@ protected VariableDeclarationSyntax GenerateIVInitCode(bool isInitLoopHead = fal { inductionVar.isLoopInitGenerated = true; loopInits.Add(VariableDeclarator(Identifier(inductionVar.Name)).WithInitializer(EqualsValueClause(inductionVar.GetLoopStart()))); - //loopInits.Add(String.Format("{0} = {1}", inductionVar.Name, inductionVar.GetLoopStart())); } } if (loopInits.Count > 0) { return VariableDeclaration(Helpers.GetToken(SyntaxKind.IntKeyword), SeparatedList(loopInits)); - //return "var " + String.Join(",", loopInits); } return null; } @@ -613,9 +600,7 @@ protected SeparatedSyntaxList GenerateIVStepCode() if (inductionVariable.LoopParameters.IsStepInLoopHeader) { inductionVariable.isLoopStepGenerated = true; - //loopInits.Add(Token(SyntaxKind.CommaToken)); loopInits.Add(inductionVariable.GetLoopStep()); - //loopInits.Add(String.Format("{0}", inductionVar.GetLoopStep())); } } @@ -630,7 +615,6 @@ protected SeparatedSyntaxList GenerateIVStepCode() } return SeparatedList(finalInits); - //return String.Join(", ", loopInits); } protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCondAtTheEnd) @@ -648,7 +632,6 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo { inductionVar.isLoopBreakGenerated = true; loopBreaks.Add(IfStatement(inductionVar.GetLoopBreakCondition(), Block(BreakStatement()))); - //loopBreaks.Add(String.Format("if {0} break;", inductionVar.GetLoopBreakCondition())); } } @@ -663,12 +646,10 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo if (inductionVar.LoopParameters.IsStepBeforeBreakCondition) { loopPreCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); - //loopPreCondSteps.Add(String.Format("{0};", inductionVar.GetLoopStep())); } else { loopPostCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); - //loopPostCondSteps.Add(String.Format("{0};", inductionVar.GetLoopStep())); } } } @@ -679,17 +660,8 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo protected ExpressionSyntax GenerateIVLoopGuardCode() { - List loopInits = new List(); - //InductionVariable inductionVariable = PrimaryInductionVariables[0]; ExpressionSyntax guardCondition = null; - //// Only generate guard condition for primary induction variables and whose LoopHeadCondition = true - //if (inductionVariable.LoopParameters.IsBreakCondInLoopHeader) - //{ - // inductionVariable.isLoopBreakGenerated = true; - // loopInits.Add(inductionVariable.GetLoopGuardCondition()); - //} - // Secondary induction variables to be incr/decr in loop body foreach (var inductionVariable in PrimaryInductionVariables) { @@ -706,12 +678,9 @@ protected ExpressionSyntax GenerateIVLoopGuardCode() { guardCondition = currCondition; } - - //loopInits.Add(inductionVariable.GetLoopGuardCondition()); } } return guardCondition; - //return String.Join("&&", loopInits); } #endregion diff --git a/Statements/WhileStatement.cs b/Statements/WhileStatement.cs new file mode 100644 index 0000000..49f6de6 --- /dev/null +++ b/Statements/WhileStatement.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.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen.Statements +{ + public class WhileStatement : LoopStatement + { + public WhileStatement(TestCase tc) : base(tc) {} + + public override List Generate(bool labels) + { + List result = new List(); + + VariableDeclarationSyntax initCode = GenerateIVInitCode(false); + if (initCode != null) + { + result.Add(LocalDeclarationStatement(initCode)); + } + + // Add step/break condition at the beginning + List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); + + // Add actual loop body + loopBody.AddRange(GetLoopBody()); + + // Add step/break condition at the end + loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); + + // guard condition + ExpressionSyntax condition = GenerateIVLoopGuardCode(); + if (condition == null) + { + condition = Bounds; + } + else + { + condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, Bounds); + } + result.Add(WhileStatement(condition, Block(loopBody))); + Debug.Assert(HasSuccessfullyGenerated(), "WhileStatement didn't generate properly. Please check the loop variables."); + + return result; + } + } +} diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 6867d32..f8463d1 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -7,6 +7,7 @@ public enum StmtKind AssignStatement, ForStatement, DoWhileStatement, + WhileStatement, } //public class Statements From 083aeff04de6282ec783edb85adcff3ee8988afc Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 30 Dec 2020 01:37:03 -0800 Subject: [PATCH 013/149] struct X { ... } --- BaseMethod.cs | 157 ++++++++++++++++---------- Helpers/VariableDeclarationHelper.cs | 103 +++++++++++++++-- README.md | 3 +- Structs.cs | 35 ++++++ TestCase.cs | 56 ++++------ TestClass.cs | 158 +++++++++++++++++++++++++++ Tree/AstUtils.cs | 11 ++ Tree/Operators.cs | 2 +- Tree/Scope.cs | 125 ++++++++++++++++++++- Tree/Types.cs | 50 ++++++++- 10 files changed, 593 insertions(+), 107 deletions(-) create mode 100644 Structs.cs create mode 100644 TestClass.cs diff --git a/BaseMethod.cs b/BaseMethod.cs index 67ec8b4..429826a 100644 --- a/BaseMethod.cs +++ b/BaseMethod.cs @@ -6,79 +6,67 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen { + /// + /// Denotes the method to generate. + /// public class BaseMethod { - private TestCase testCase; + private TestClass testClass; + private TestCase TC => testClass.TC; private string Name; #if DEBUG - private bool annotateComments = true; private Dictionary expressionsCount = new Dictionary(); - private Dictionary statementsCount = new Dictionary(); -#else - private bool annotateComments = false; + private Dictionary statementsCount = new Dictionary(); #endif - private List variableNames = new List(); - private Scope m_ParentScope; - private Stack ScopeStack = new Stack(); + private int variablesCount = 0; - public MethodDeclarationSyntax GeneratedMethod { get; private set; } + private Scope m_ParentScope; + //private Stack ScopeStack = new Stack(); public AstUtils GetASTUtils() { - return testCase.AstUtils; - } - - public void AddParentScope(Scope parent) - { - m_ParentScope = parent; + return TC.AstUtils; } - public Scope GetParentScope() - { - if (m_ParentScope != null) - return m_ParentScope; - else - return null; - } - - public Scope CurrentScope - { - get { return ScopeStack.Peek(); } - } + private Scope MethodScope; + public Scope CurrentScope => testClass.CurrentScope; public void PushScope(Scope scope) { - ScopeStack.Push(scope); + testClass.PushScope(scope); } public Scope PopScope() { - Scope ret = ScopeStack.Pop(); + Scope ret = testClass.PopScope(); //Debug.Assert(ret.Parent == ScopeStack.Peek()); return ret; } - public BaseMethod(TestCase tc, string name) + public BaseMethod(TestClass enclosingClass, string methodName) { - testCase = tc; - Name = name; + testClass = enclosingClass; + Name = methodName; + MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); } - public void Generate() + public MethodDeclarationSyntax Generate() { + PushScope(MethodScope); + MethodDeclarationSyntax methodDeclaration = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Name).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); IList methodBody = new List(); // TODO-TEMP initialize one variable of each type foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { - string variableName = Helpers.GetVariableName(variableType, variableNames.Count); - variableNames.Add(variableName); + string variableName = Helpers.GetVariableName(variableType, variablesCount++); ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); @@ -86,6 +74,24 @@ public void Generate() methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs))); } + // TODO-TEMP initialize one variable of each struct type + foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) + { + string variableName = Helpers.GetVariableName(structType, variablesCount++); + + ExpressionSyntax rhs = Annotate(Helpers.GetObjectCreationExpression(structType.TypeName), "struct-init"); + CurrentScope.AddLocal(structType, variableName); + + // Add all the fields to the scope + var listOfStructFields = CurrentScope.GetStructFields(structType); + foreach(var structField in listOfStructFields) + { + CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); + } + + methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(structType, variableName, rhs))); + } + //TODO: Define some more constants methodBody.Add( LocalDeclarationStatement( @@ -106,8 +112,10 @@ public void Generate() methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); } + PopScope(); + // Wrap everything in unchecked so we do not see overflow compilation errors - GeneratedMethod = methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); + return methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); } public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) @@ -116,13 +124,32 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { case StmtKind.VariableDeclaration: { - Tree.ValueType variableType = GetASTUtils().GetRandomExprType(); - string variableName = Helpers.GetVariableName(variableType, variableNames.Count); - variableNames.Add(variableName); + Tree.ValueType variableType; + //TODO:config - probability of struct variables + if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) + { + variableType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + } + else + { + variableType = GetASTUtils().GetRandomExprType(); + } + + string variableName = Helpers.GetVariableName(variableType, variablesCount++); ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); + // Add all the fields to the scope + if (variableType.PrimitiveType == Primitive.Struct) + { + var listOfStructFields = CurrentScope.GetStructFields(variableType); + foreach (var structField in listOfStructFields) + { + CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); + } + } + return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "VarDecl"); } case StmtKind.IfElseStatement: @@ -130,8 +157,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); - Scope ifBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); - Scope elseBranchScope = new Scope(testCase, ScopeKind.ConditionalScope, CurrentScope); + Scope ifBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); + Scope elseBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); //TODO-config: Add MaxDepth in config int ifcount = 3; @@ -179,15 +206,27 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) case StmtKind.AssignStatement: { Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); - Tree.ValueType variableType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + Tree.ValueType variableType; + //TODO-cleanup: Somehow combine GetRandomExprType() and GetRandomStructType() functionality + // Currently the only problem is AllStructTypes is in scope object but GetRandomExprType() is + // in AstUtils. + if (((assignOper.InputTypes & Primitive.Struct) != 0) && PRNG.Decide(0.2) && CurrentScope.NumOfStructTypes > 0) + { + variableType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + } + else + { + variableType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + } + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, variableType, depth); ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, depth); return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); } case StmtKind.ForStatement: { - Scope forLoopScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); - ForStatement forStmt = new ForStatement(testCase); + Scope forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); + ForStatement forStmt = new ForStatement(TC); //TODO:config int n = 3; // max statements forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int32)); @@ -230,8 +269,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.DoWhileStatement: { - Scope doWhileScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); - DoWhileStatement doStmt = new DoWhileStatement(testCase); + Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); + DoWhileStatement doStmt = new DoWhileStatement(TC); //TODO:config int n = 3; // max statements doStmt.NestNum = depth; @@ -263,8 +302,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.WhileStatement: { - Scope whileScope = new Scope(testCase, ScopeKind.LoopScope, CurrentScope); - WhileStatement whileStmt = new WhileStatement(testCase); + Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); + WhileStatement whileStmt = new WhileStatement(TC); //TODO:config int n = 3; // max statements whileStmt.NestNum = depth; @@ -309,7 +348,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); case ExprKind.VariableExpression: - return Annotate(IdentifierName(CurrentScope.GetRandomVariable(exprType)), "Var"); + return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); case ExprKind.BinaryOpExpression: Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); @@ -336,19 +375,16 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); default: - Debug.Assert(false, String.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); + Debug.Assert(false, string.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); break; } return null; } + private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) { - if (!annotateComments) - { - return expression; - } - +#if DEBUG string typeName = expression.GetType().Name; if (!expressionsCount.ContainsKey(typeName)) { @@ -356,14 +392,14 @@ private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) } expressionsCount[typeName]++; return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{expressionsCount[typeName]}: {comment} */"))); +#else + return expression; +#endif } private StatementSyntax Annotate(StatementSyntax statement, string comment) { - if (!annotateComments) - { - return statement; - } +#if DEBUG string typeName = statement.GetType().Name; if (!statementsCount.ContainsKey(typeName)) { @@ -371,6 +407,9 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment) } statementsCount[typeName]++; return statement.WithTrailingTrivia(TriviaList(Comment($"/* S#{statementsCount[typeName]}: {comment} */"))); +#else + return statement; +#endif } } } diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs index 4082f0f..5b6eda2 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Helpers/VariableDeclarationHelper.cs @@ -14,27 +14,108 @@ namespace Antigen { public static partial class Helpers { - public static VariableDeclarationSyntax GetVariableDeclaration(Tree.ValueType variableType, string variableName, ExpressionSyntax value) + public static VariableDeclarationSyntax GetVariableDeclaration(Tree.ValueType variableType, string variableName, ExpressionSyntax value = null) { - return VariableDeclaration( - PredefinedType( - Token(variableType.TypeKind))) - .WithVariables( - SingletonSeparatedList( - VariableDeclarator( - Identifier(variableName)) - .WithInitializer( - EqualsValueClause(value)))); + VariableDeclarationSyntax varDecl; + if (variableType.PrimitiveType == Primitive.Struct) + { + varDecl = GetVariableDeclaration(variableType.TypeName, variableName); + } + else + { + varDecl = VariableDeclaration(PredefinedType(Token(variableType.TypeKind))); + } + + var declarator = VariableDeclarator(Identifier(variableName)); + if (value != null) + { + declarator = declarator.WithInitializer(EqualsValueClause(value)); + } + return varDecl.WithVariables(SingletonSeparatedList(declarator)); + } + + private static VariableDeclarationSyntax GetVariableDeclaration(string variableType, string variableName) + { + TypeSyntax variableTypeSyntax; + if (variableType.Contains(".")) + { + string[] seperatedTypes = variableType.Split('.', StringSplitOptions.RemoveEmptyEntries); + NameSyntax nameSyntax = QualifiedName( + IdentifierName(seperatedTypes[0]), + IdentifierName(seperatedTypes[1])); + for (int subType = 2; subType < seperatedTypes.Length; subType++) + { + nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); + } + variableTypeSyntax = nameSyntax; + } + else + { + variableTypeSyntax = IdentifierName(variableType); + } + + var varDecl = VariableDeclarator(Identifier(variableName)); + return VariableDeclaration(variableTypeSyntax) + .WithVariables(SingletonSeparatedList(varDecl)); } public static string GetVariableName(Tree.ValueType variableType, int id) { - return Enum.GetName(typeof(SpecialType), variableType.DataType).Replace("System_", "").ToLower() + "_" + id; + return variableType.VariableNameHint() + "_" + id; } public static PredefinedTypeSyntax GetToken(SyntaxKind syntaxKind) { return PredefinedType(Token(syntaxKind)); } + + public static ExpressionSyntax GetVariableAccessExpression(string variableName) + { + if (variableName.Contains(".")) + { + string[] seperatedFields = variableName.Split('.', StringSplitOptions.RemoveEmptyEntries); + var memberAccessExpr = MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(seperatedFields[0]), + IdentifierName(seperatedFields[1])); + for (int subType = 2; subType < seperatedFields.Length; subType++) + { + memberAccessExpr = MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + memberAccessExpr, + IdentifierName(seperatedFields[subType])); + } + + return memberAccessExpr; + } + else + { + return IdentifierName(variableName); + } + } + + public static ObjectCreationExpressionSyntax GetObjectCreationExpression(string objectType) + { + TypeSyntax objectTypeSyntax; + + if (objectType.Contains(".")) + { + string[] seperatedTypes = objectType.Split('.', StringSplitOptions.RemoveEmptyEntries); + NameSyntax nameSyntax = QualifiedName( + IdentifierName(seperatedTypes[0]), + IdentifierName(seperatedTypes[1])); + for (int subType = 2; subType < seperatedTypes.Length; subType++) + { + nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); + } + objectTypeSyntax = nameSyntax; + } + else + { + objectTypeSyntax = IdentifierName(objectType); + } + return ObjectCreationExpression(objectTypeSyntax).WithArgumentList( + ArgumentList()); + } } } diff --git a/README.md b/README.md index e93a7e7..462b4c0 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 5. Assignment statement, /* S:Assign */ annotation 6. For-loop 7. Do-While loop -8. While loop \ No newline at end of file +8. While loop +9. struct \ No newline at end of file diff --git a/Structs.cs b/Structs.cs new file mode 100644 index 0000000..0ed2edc --- /dev/null +++ b/Structs.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; + +namespace Antigen +{ + /// + /// Represents a field present in a struct. This is useful to + /// expand the fully qualifier name of a field present inside a + /// nested struct. + /// + public struct StructField + { + public string FieldName; + public Tree.ValueType FieldType; + + public StructField(Tree.ValueType type, string name) + { + FieldType = type; + FieldName = name; + } + + public override string ToString() + { + return $"{Enum.GetName(typeof(Primitive), FieldType.PrimitiveType)} {FieldName}"; + } + } +} diff --git a/TestCase.cs b/TestCase.cs index f6a3f8d..b0c16c5 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -29,9 +30,8 @@ public enum CompilationType private const string MainMethodName = "Method0"; - private SyntaxNode testClass; + private SyntaxNode testCase; - private Scope GlobalScope; //private List classesList; //private List methodsList; //private List propertiesList; @@ -48,31 +48,22 @@ public TestCase(int testId) public void Generate() { - GlobalScope = new Scope(this); - - IList methods = new List(); - - for (int i = 0; i < 1; i++) - { - var testMethod = new BaseMethod(this, "Method" + i); - methods.Add(testMethod); - - Scope localScope = new Scope(this, ScopeKind.FunctionScope, GlobalScope); - - testMethod.PushScope(localScope); - - testMethod.Generate(); - testMethod.PopScope(); - } - - ClassDeclarationSyntax klass = ClassDeclaration(Name).WithMembers(new SyntaxList(methods.Select(m => m.GeneratedMethod))); - testClass = CompilationUnit() - .WithUsings( - SingletonList( - UsingDirective( - IdentifierName("System")))) - .WithMembers( - SingletonList(klass)).NormalizeWhitespace(); + UsingDirectiveSyntax usingDirective = + UsingDirective(IdentifierName("System")) + .WithUsingKeyword(Token(TriviaList(new[]{ + Comment("// Licensed to the .NET Foundation under one or more agreements."), + Comment("// The .NET Foundation licenses this file to you under the MIT license."), + Comment("// See the LICENSE file in the project root for more information."), + Comment("//"), + Comment("// This file is auto-generated."), + Comment("//"), + }), SyntaxKind.UsingKeyword, TriviaList())); + + ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); + + testCase = CompilationUnit() + .WithUsings(SingletonList(usingDirective)) + .WithMembers(new SyntaxList(klass)).NormalizeWhitespace(); } public void CompileAndExecute() @@ -83,16 +74,17 @@ public void CompileAndExecute() private CompileResult Compile(CompilationType compilationType) { - string testClassContents = testClass.ToFullString(); - File.WriteAllText(@"E:\git\Antigen\TestClass.g.cs", testClassContents); + string testCaseContents = testCase.ToFullString(); + File.WriteAllText(@$"E:\git\Antigen\{Name}.g.cs", testCaseContents); - string[] testClassCode = testClassContents.Split(Environment.NewLine); + string[] testCaseCode = testCaseContents.Split(Environment.NewLine); int lineNum = 1; - foreach (string code in testClassCode) + foreach (string code in testCaseCode) { Console.WriteLine("[{0,4:D4}]{1}", lineNum++, code); } + SyntaxTree syntaxTree = testCase.SyntaxTree; string corelibPath = typeof(object).Assembly.Location; string otherAssembliesPath = Path.GetDirectoryName(corelibPath); MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); @@ -103,7 +95,7 @@ private CompileResult Compile(CompilationType compilationType) MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - var cc = CSharpCompilation.Create(Name, new SyntaxTree[] { testClass.SyntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); + var cc = CSharpCompilation.Create(Name, new SyntaxTree[] { syntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); using (var ms = new MemoryStream()) { diff --git a/TestClass.cs b/TestClass.cs new file mode 100644 index 0000000..1aebef9 --- /dev/null +++ b/TestClass.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen +{ + /// + /// Denotes the class to generate. + /// + public class TestClass + { + public Scope ClassScope { get; private set; } + public string ClassName; + public TestCase TC { get; private set; } + public Stack ScopeStack { get; private set; } + + public AstUtils GetASTUtils() + { + return TC.AstUtils; + } + + public TestClass(TestCase tc, string className) + { + ScopeStack = new Stack(); + ClassScope = new Scope(tc); + ClassName = className; + TC = tc; + } + + public Scope CurrentScope + { + get { return ScopeStack.Peek(); } + } + + public void PushScope(Scope scope) + { + ScopeStack.Push(scope); + } + + public Scope PopScope() + { + Scope ret = ScopeStack.Pop(); + //Debug.Assert(ret.Parent == ScopeStack.Peek()); + return ret; + } + + public ClassDeclarationSyntax Generate() + { + // push class scope + PushScope(ClassScope); + + List classMembers = new List(); + classMembers.AddRange(GenerateStructs()); + classMembers.AddRange(GenerateMethods()); + + // pop class scope + PopScope(); + + return ClassDeclaration(ClassName) + .WithMembers(new SyntaxList(classMembers)); + } + + /// + /// Generate structs in this class + /// + /// + private List GenerateStructs() + { + List structs = new List(); + + //TODO:config - number of structs + for (int structIndex = 1; structIndex <= 5; structIndex++) + { + string structName = $"S{structIndex}"; + var (structDecl, fields) = GenerateStruct(structName, structName, structIndex, 1); + structs.Add(structDecl); + CurrentScope.AddStructType(structName, fields); + } + + (MemberDeclarationSyntax, List) GenerateStruct(string structName, string structType, int structIndex, int depth) + { + StructDeclarationSyntax structDeclaration = StructDeclaration(structName) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + + List fieldsTree = new List(); + List fieldsMetadata = new List(); + //TODO: config - number of fields + int fieldCount = PRNG.Next(1, 5); + for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) + { + //TODO:config - probability of nested structs + //TODO:config - struct nested depth + if (PRNG.Decide(0.1) && depth < 3) + { + string nestedStructName = $"S{structIndex}_D{depth}_F{fieldIndex}"; + string nestedStructType = structType + "." + nestedStructName; + var (structDecl, childFields) = GenerateStruct(nestedStructName, nestedStructType, structIndex, depth + 1); + fieldsTree.Add(structDecl); + CurrentScope.AddStructType(nestedStructType, childFields); + structName = nestedStructName; + continue; + } + + Tree.ValueType fieldType; + string fieldName; + + //TODO:config - probability of fields of type struct + if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) + { + fieldType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + } + else + { + fieldType = GetASTUtils().GetRandomExprType(); + } + + fieldName = Helpers.GetVariableName(fieldType, fieldIndex); + fieldsTree.Add(FieldDeclaration(Helpers.GetVariableDeclaration(fieldType, fieldName)).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); + fieldsMetadata.Add(new StructField(fieldType, fieldName)); + } + + return (structDeclaration.WithMembers(new SyntaxList(fieldsTree)), fieldsMetadata); + } + + return structs; + } + + /// + /// Generate methods in this class + /// + /// + private IList GenerateMethods() + { + List methods = new List(); + + //TODO-config: No. of methods per class + for (int i = 0; i < 1; i++) + { + var testMethod = new BaseMethod(this, "Method" + i); + methods.Add(testMethod.Generate()); + } + + return methods; + } + } +} diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 4ca86ac..13357d8 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -9,6 +9,7 @@ public class AstUtils { private List> AllExpressions = new List>(); private List> AllNonNumericExpressions = new List>(); + private List> AllStructExpressions = new List>(); private List> AllStatements = new List>(); private List> AllTypes = new List>(); private List> AllStatementsWithCFStmts = new List>(); @@ -49,6 +50,11 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) { AllNonNumericExpressions.Add(new Weights(expr, Options.Lookup(expr))); } + + if (expr == ExprKind.VariableExpression) + { + AllStructExpressions.Add(new Weights(expr, Options.Lookup(expr))); + } } // Initialize operators @@ -105,6 +111,11 @@ public ExprKind GetRandomExpressionReturningPrimitive(Primitive returnPrimitiveT exprs = from z in AllNonNumericExpressions select z; } + else if (returnPrimitiveType == Primitive.Struct) + { + exprs = from z in AllStructExpressions + select z; + } else { exprs = from z in AllExpressions diff --git a/Tree/Operators.cs b/Tree/Operators.cs index 605f088..c0dfd2d 100644 --- a/Tree/Operators.cs +++ b/Tree/Operators.cs @@ -65,7 +65,7 @@ public bool HasReturnType(Primitive valueType) new Operator(SyntaxKind.LeftShiftExpression, "i<>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), - new Operator(SyntaxKind.SimpleAssignmentExpression, "i=j", Primitive.Any, Primitive.Any, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.SimpleAssignmentExpression, "i=j", Primitive.Any | Primitive.Struct, Primitive.Any | Primitive.Struct, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), new Operator(SyntaxKind.AddAssignmentExpression, "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), new Operator(SyntaxKind.SubtractAssignmentExpression, "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), new Operator(SyntaxKind.MultiplyAssignmentExpression, "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), diff --git a/Tree/Scope.cs b/Tree/Scope.cs index 80aa25c..b643190 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -38,6 +38,13 @@ public class Scope public List AllVariables => LocalVariables.SelectMany(dict => dict.Value).ToList(); + // A mapping of all the primitive fields present in given struct + // Every time a variable "xyz" of one of the struct is defined, all the fields corresponding to that struct + // will be added to the scope in the form "xyz.field1", "xyz.field2" and so forth. + public Dictionary> StructToFieldsMapping = new Dictionary>(); + + private List ListOfStructTypes = new List(); + // List of string vars in the current scope. private List LocalStringVariables = new List(); @@ -57,12 +64,18 @@ public Scope(TestCase tc, ScopeKind t, Scope parentScope) #endregion - #region Get variables from the scope + #region Get variables/types from the scope public string GetRandomVariable(ValueType variableType) { List allUsableVariables = GetUsableVariables(variableType); return allUsableVariables[PRNG.Next(allUsableVariables.Count)]; } + + public ValueType GetRandomStructType() + { + return ListOfStructTypes[PRNG.Next(ListOfStructTypes.Count)]; + } + #endregion #region Gets From Scope @@ -72,7 +85,7 @@ public int GetVariablesCount() } #endregion - #region Add variables to scope + #region Add variables/types to scope public void AddLocal(ValueType variableType, string variableName) { #if DEBUG @@ -102,6 +115,52 @@ public void AddLocal(ValueType variableType, string variableName) ListOfVariables[variableType].Add(variableName); } + + /// + /// Adds the struct type in the list of types + /// defined in current scope. + /// + /// It also resolves all the fields present in + /// and store the fully qualifier name in . + /// + public void AddStructType(string typeName, List structFields) + { + ValueType newStructType = ValueType.CreateStructType(typeName); + List fieldsInCurrStruct = new List(); + + foreach (StructField field in structFields) + { + if (StructToFieldsMapping.TryGetValue(field.FieldType, out List childFields)) + { + // If the field type is present in structToFieldsMapping, meaning the field is a struct + Debug.Assert(field.FieldType.PrimitiveType == Primitive.Struct); + + foreach (StructField childField in childFields) + { + // structs present in structToFieldsMapping should have all the child fields expanded. + Debug.Assert((childField.FieldType.PrimitiveType & Primitive.Any) != 0); + + string expandedFieldName = field.FieldName + "." + childField.FieldName; + + fieldsInCurrStruct.Add(new StructField(childField.FieldType, expandedFieldName)); + } + } + else + { + // else it is a primitive + Debug.Assert((field.FieldType.PrimitiveType & Primitive.Any) != 0); + + //string expandedFieldName = field.FieldName + "." + childField.FieldName; + + fieldsInCurrStruct.Add(new StructField(field.FieldType, field.FieldName)); + } + } + + Debug.Assert(!StructToFieldsMapping.ContainsKey(newStructType)); + StructToFieldsMapping[newStructType] = fieldsInCurrStruct; + + ListOfStructTypes.Add(newStructType); + } #endregion #region Aggregate Scopes methods @@ -126,6 +185,68 @@ private List GetUsableVariables(ValueType variableType) } return variables; } + + /// + /// Counts number of struct types defined so far in + /// current scope or parent scope. + /// + public int NumOfStructTypes + { + get + { + int count = 0; + + Scope curr = this; + + while (curr != null) + { + count += curr.ListOfStructTypes.Count; + curr = curr.parent; + } + return count; + } + } + + /// + /// Returns all the struct types defined in current + /// and parent scopes. + /// + public List AllStructTypes + { + get + { + List result = new List(); + Scope curr = this; + + while (curr != null) + { + result.AddRange(curr.ListOfStructTypes); + curr = curr.parent; + } + return result; + } + } + + /// + /// Get all the fields (having fully qualifier name) present in + /// . + /// + public List GetStructFields(Tree.ValueType structType) + { + List result = null; + Scope curr = this; + + while (curr != null) + { + if (curr.StructToFieldsMapping.TryGetValue(structType, out result)) + { + return result; + } + + curr = curr.parent; + } + return result; + } #endregion } } diff --git a/Tree/Types.cs b/Tree/Types.cs index 713aa5f..8c3f0fb 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis.CSharp; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Antigen.Tree @@ -36,6 +37,7 @@ public enum Primitive : ulong UInt16 = 0x800, UInt32 = 0x1000, UInt64 = 0x2000, + Struct = 0x4000, Numeric = Byte | Decimal | Double | Int16 | Int32 | Int64 | SByte | Single | UInt16 | UInt32 | UInt64, SignedInteger = SByte | Int16 | Int32 | Int64, @@ -55,6 +57,16 @@ public bool AllowedPrimitive(Primitive primitives) return val; } + public string TypeName + { + get + { + Debug.Assert(PrimitiveType == Primitive.Struct); + return _structTypeName; + } + } + + private string _structTypeName; public Primitive PrimitiveType; //private TypeFlags Flags; public SpecialType DataType; @@ -78,11 +90,19 @@ public bool AllowedPrimitive(Primitive primitives) new ValueType(Primitive.UInt64, SpecialType.System_UInt64, SyntaxKind.ULongKeyword), }; + public static ValueType CreateStructType(string typeName) + { + var structType = new ValueType(Primitive.Struct, SpecialType.None, SyntaxKind.None); + structType._structTypeName = typeName; + return structType; + } + private ValueType(Primitive valueType, SpecialType dataType, SyntaxKind typeKind) { PrimitiveType = valueType; DataType = dataType; TypeKind = typeKind; + _structTypeName = null; } public static List GetTypes() @@ -90,14 +110,42 @@ public static List GetTypes() return types; } + public override bool Equals(object obj) + { + ValueType otherType = (ValueType)obj; + return PrimitiveType == otherType.PrimitiveType && + DataType == otherType.DataType && + TypeKind == otherType.TypeKind && + _structTypeName == otherType._structTypeName; + } + public static ValueType ForPrimitive(Primitive primitiveType) { return types.First(t => t.PrimitiveType == primitiveType); } + public string VariableNameHint() + { + if (PrimitiveType != Primitive.Struct) + { + return Enum.GetName(typeof(SpecialType), DataType).Replace("System_", "").ToLower(); + } + else + { + return TypeName.ToLower().Replace(".", "_").ToLower(); + } + } + public override string ToString() { - return Enum.GetName(typeof(Primitive), PrimitiveType); + if (PrimitiveType != Primitive.Struct) + { + return Enum.GetName(typeof(Primitive), PrimitiveType); + } + else + { + return $"struct {_structTypeName}"; + } } } } From 2f0740af67d5b5209daba53f68122fa9d2025539 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 30 Dec 2020 01:37:25 -0800 Subject: [PATCH 014/149] Add FindDiff() in DEBUG - Rename BaseMethod to TestMethod --- Antigen.csproj | 10 ++-- TestCase.cs | 85 +++++++++++++++++++++++++--------- TestClass.cs | 2 +- BaseMethod.cs => TestMethod.cs | 4 +- 4 files changed, 70 insertions(+), 31 deletions(-) rename BaseMethod.cs => TestMethod.cs (99%) diff --git a/Antigen.csproj b/Antigen.csproj index dbc857c..68061ba 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -8,13 +8,13 @@ - - + + - + + + diff --git a/TestCase.cs b/TestCase.cs index b0c16c5..07e376d 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -72,6 +72,40 @@ public void CompileAndExecute() Execute(compileResult); } + /// + /// Method to find diff of generated tree vs. roslyn generated tree by parsing the + /// generated code. + /// + /// + /// + private void FindDiff(SyntaxNode expected, SyntaxNode actual) + { + if ((expected is LiteralExpressionSyntax) || (actual is LiteralExpressionSyntax)) + { + // ignore + return; + } + + if (!expected.IsEquivalentTo(actual)) + { + var expectedChildNodes = expected.ChildNodes().ToArray(); + var actualChildNodes = actual.ChildNodes().ToArray(); + + int expectedCount = expectedChildNodes.Length; + int actualCount = actualChildNodes.Length; + if (expectedCount != actualCount) + { + Debug.Assert(false, $"Child nodes mismatch. Expected= {expected}, Actual= {actual}"); + return; + } + for (int ch = 0; ch < expectedCount; ch++) + { + FindDiff(expectedChildNodes[ch], actualChildNodes[ch]); + } + return; + } + } + private CompileResult Compile(CompilationType compilationType) { string testCaseContents = testCase.ToFullString(); @@ -84,7 +118,17 @@ private CompileResult Compile(CompilationType compilationType) Console.WriteLine("[{0,4:D4}]{1}", lineNum++, code); } +#if DEBUG SyntaxTree syntaxTree = testCase.SyntaxTree; + SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCase.ToFullString()); + FindDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); +#else + // In release, make sure that we didn't end up generating wrong syntax tree, + // hence parse the text to reconstruct the tree. + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCase.ToFullString()); +#endif + string corelibPath = typeof(object).Assembly.Location; string otherAssembliesPath = Path.GetDirectoryName(corelibPath); MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); @@ -122,7 +166,7 @@ private void Execute(CompileResult compileResult) { if (compileResult.Assembly == null) { - Console.WriteLine("Got compiler errors:"); + Console.WriteLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); Console.WriteLine(string.Join(Environment.NewLine, compileResult.CompileErrors)); Console.ReadLine(); } @@ -159,35 +203,30 @@ private void Execute(CompileResult compileResult) internal class CompileResult { - public CompileResult(Exception roslynException, ImmutableArray compileErrors, byte[] assembly) + public CompileResult(Exception roslynException, ImmutableArray diagnostics, byte[] assembly) { RoslynException = roslynException; - CompileErrors = compileErrors; + List errors = new List(); + List warnings = new List(); + foreach (var diag in diagnostics) + { + if (diag.Severity == DiagnosticSeverity.Error) + { + errors.Add(diag); + } + else if (diag.Severity == DiagnosticSeverity.Warning) + { + errors.Add(diag); + } + } + CompileErrors = errors.ToImmutableArray(); + CompileWarnings = warnings.ToImmutableArray(); Assembly = assembly; } public Exception RoslynException { get; } public ImmutableArray CompileErrors { get; } + public ImmutableArray CompileWarnings { get; } public byte[] Assembly { get; } } - - //public class TestClass - //{ - - //} - - //public class TestMainClass : TestClass - //{ - - //} - - //public class TestMethod - //{ - - //} - - //public class TestMainMethod : TestMethod - //{ - - //} } diff --git a/TestClass.cs b/TestClass.cs index 1aebef9..5b0f6f7 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -148,7 +148,7 @@ private IList GenerateMethods() //TODO-config: No. of methods per class for (int i = 0; i < 1; i++) { - var testMethod = new BaseMethod(this, "Method" + i); + var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); } diff --git a/BaseMethod.cs b/TestMethod.cs similarity index 99% rename from BaseMethod.cs rename to TestMethod.cs index 429826a..573eb2e 100644 --- a/BaseMethod.cs +++ b/TestMethod.cs @@ -14,7 +14,7 @@ namespace Antigen /// /// Denotes the method to generate. /// - public class BaseMethod + public class TestMethod { private TestClass testClass; private TestCase TC => testClass.TC; @@ -49,7 +49,7 @@ public Scope PopScope() return ret; } - public BaseMethod(TestClass enclosingClass, string methodName) + public TestMethod(TestClass enclosingClass, string methodName) { testClass = enclosingClass; Name = methodName; From 0b6916a4ce0a5d864d6c9f15761fbac1a8164cf4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 2 Jan 2021 09:45:29 -0800 Subject: [PATCH 015/149] Introduce Main() --- TestCase.cs | 23 +++++++++++++++-------- TestClass.cs | 7 +++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/TestCase.cs b/TestCase.cs index 07e376d..9e5acc9 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen @@ -28,7 +29,7 @@ public enum CompilationType #region PreComputed roslyn syntax tress #endregion - private const string MainMethodName = "Method0"; + private const string MainMethodName = "Main"; private SyntaxNode testCase; @@ -56,6 +57,7 @@ public void Generate() Comment("// See the LICENSE file in the project root for more information."), Comment("//"), Comment("// This file is auto-generated."), + Comment("// Seed: " + PRNG.GetSeed()), Comment("//"), }), SyntaxKind.UsingKeyword, TriviaList())); @@ -175,28 +177,33 @@ private void Execute(CompileResult compileResult) Assembly asm = Assembly.Load(compileResult.Assembly); Type testClassType = asm.GetType(Name); MethodInfo mainMethodInfo = testClassType.GetMethod(MainMethodName); - MainMethodInvoke entryPoint = (MainMethodInvoke)Delegate.CreateDelegate(typeof(MainMethodInvoke), Activator.CreateInstance(testClassType), mainMethodInfo); + Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); Exception ex = null; - //TextWriter origOut = Console.Out; + TextWriter origOut = Console.Out; MemoryStream ms = new MemoryStream(); - //StreamWriter sw = new StreamWriter(Console.s, Encoding.UTF8); + StreamWriter sw = new StreamWriter(ms, Encoding.UTF8); try { - //Console.SetOut(sw); - entryPoint(); + Console.SetOut(sw); + entryPoint(null); } catch (Exception caughtEx) { ex = caughtEx; + Console.WriteLine(caughtEx); } finally { - //Console.SetOut(origOut); - //sw.Close(); + Console.SetOut(origOut); + sw.Close(); } + + string stdout = Encoding.UTF8.GetString(ms.ToArray()); + Console.WriteLine(stdout); + Console.ReadLine(); } } } diff --git a/TestClass.cs b/TestClass.cs index 5b0f6f7..302ae51 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -145,6 +145,13 @@ private IList GenerateMethods() { List methods = new List(); + methods.Add(ParseMemberDeclaration( +@$"public static void Main(string[] args) {{ + {ClassName} obj{ClassName} = new {ClassName}(); + obj{ClassName}.Method0(); +}} +")); + //TODO-config: No. of methods per class for (int i = 0; i < 1; i++) { From b64ff5e4a920fd67fb35aa1e8db757ba0102c641 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 2 Jan 2021 09:46:40 -0800 Subject: [PATCH 016/149] fix compilation errors related to /, %, << and >> --- Config/ConfigOptions.cs | 2 +- Helpers/Literals.cs | 2 -- TestMethod.cs | 75 ++++++++++++++++++++++++++++++++--------- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 126d90b..23acc8e 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -14,7 +14,7 @@ public class ConfigOptions : OptionsBase public const string WeightSuffix = "Weight"; // Expression weights - public double LiteralWeight = 0.25; + public double LiteralWeight = 0.025; public double VariableWeight = 0.5; public double BinaryOpWeight = 1; diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index 93dcaa0..556d298 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -172,8 +172,6 @@ public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType litera } return LiteralExpression(kind, literalToken); - - //return LiteralExpression(kind, literalToken); } } } diff --git a/TestMethod.cs b/TestMethod.cs index 573eb2e..7074afd 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -26,9 +26,6 @@ public class TestMethod private int variablesCount = 0; - private Scope m_ParentScope; - //private Stack ScopeStack = new Stack(); - public AstUtils GetASTUtils() { return TC.AstUtils; @@ -206,21 +203,38 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) case StmtKind.AssignStatement: { Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); - Tree.ValueType variableType; + Tree.ValueType lhsExprType, rhsExprType; //TODO-cleanup: Somehow combine GetRandomExprType() and GetRandomStructType() functionality // Currently the only problem is AllStructTypes is in scope object but GetRandomExprType() is // in AstUtils. if (((assignOper.InputTypes & Primitive.Struct) != 0) && PRNG.Decide(0.2) && CurrentScope.NumOfStructTypes > 0) { - variableType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + lhsExprType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + } + else + { + lhsExprType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + } + + if (assignOper.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int32); } else { - variableType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + rhsExprType = lhsExprType; + } + + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + + // For division, make sure that divisor is not 0 + if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) + { + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, rhs); } - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, variableType, depth); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, depth); return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); } case StmtKind.ForStatement: @@ -351,27 +365,56 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); case ExprKind.BinaryOpExpression: - Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: exprType.PrimitiveType); - - Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + Primitive returnType = exprType.PrimitiveType; + + Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); + + // If the return type is boolean, then take any ExprType that returns boolean. + // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. + //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, + // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and + // the literals are selected of different type ("decimal" in this example) and we get compilation error + // because they can't be casted to short. + Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); + //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); Tree.ValueType rhsExprType = lhsExprType; + if (op.HasFlag(OpFlags.Shift)) { rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int32); } - ExpressionSyntax lhs, rhs; + ExprKind lhsExprKind, rhsExprKind; //TODO-config: Add MaxDepth in config if (depth >= 5) { - lhs = ExprHelper(ExprKind.LiteralExpression, lhsExprType, 0); - rhs = ExprHelper(ExprKind.LiteralExpression, rhsExprType, 0); + lhsExprKind = rhsExprKind = ExprKind.LiteralExpression; } else { - lhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType), lhsExprType, depth + 1); - rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth + 1); + lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); + rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + } + + // Fold arithmetic binop expressions that has constants. + // csc.exe would automatically fold that for us, but by doing it here, we eliminate generate + // errors during compiling the test case. + if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) + { + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); } + + //TODO-config: Add MaxDepth in config + ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth >= 5 ? 0 : depth + 1); + ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth >= 5 ? 0 : depth + 1); + + // For division, make sure that divisor is not 0 + if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) + { + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, rhs); + } + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); default: From 0ef4e93fb70132fe70c2742f559ac40385973507 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 2 Jan 2021 09:47:11 -0800 Subject: [PATCH 017/149] Introduce implicit/explicit conversion experiment - Rename PrimitiveType enums to meaningful --- Helpers/Expressions.cs | 17 +++++- Helpers/Literals.cs | 14 ++--- Program.cs | 4 +- TestMethod.cs | 20 +++---- Tree/Types.cs | 120 ++++++++++++++++++++++++++++++++++------- 5 files changed, 136 insertions(+), 39 deletions(-) diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index 2411e1d..5c0fc28 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Text; @@ -18,9 +19,21 @@ public static BinaryExpressionSyntax GetBinaryExpression(ExpressionSyntax lhs, O return BinaryExpression(op.Oper, lhs, rhs); } - public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueType returnType, ExpressionSyntax expr) + public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueType fromType, ValueType toType, ExpressionSyntax expr) { - return ParenthesizedExpression(CastExpression(Helpers.GetToken(returnType.TypeKind), ParenthesizedExpression(expr))); + //Debug.Assert(fromType.CanConvert(toType) || toType.PrimitiveType == Primitive.Boolean); + ParenthesizedExpressionSyntax parenExpr = ParenthesizedExpression(expr); + + //if (fromType.CanConvertExplicit(toType)) + //{ + parenExpr = ParenthesizedExpression(CastExpression(Helpers.GetToken(toType.TypeKind), parenExpr)); + //} + //else + //{ + // Debug.Assert(fromType.CanConvertImplicit(toType) || toType.PrimitiveType == Primitive.Boolean); + //} + + return parenExpr; } } } diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index 556d298..7eba775 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -118,27 +118,27 @@ public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType litera kind = SyntaxKind.CharacterLiteralExpression; literalToken = Literal(GetRandomChar()); break; - case Tree.Primitive.Int16: + case Tree.Primitive.Short: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomShort()); break; - case Tree.Primitive.Int32: + case Tree.Primitive.Int: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomInt()); break; - case Tree.Primitive.Int64: + case Tree.Primitive.Long: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomLong()); break; - case Tree.Primitive.UInt16: + case Tree.Primitive.UShort: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomUShort()); break; - case Tree.Primitive.UInt32: + case Tree.Primitive.UInt: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomUInt()); break; - case Tree.Primitive.UInt64: + case Tree.Primitive.ULong: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomULong()); break; @@ -146,7 +146,7 @@ public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType litera kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomSByte()); break; - case Tree.Primitive.Single: + case Tree.Primitive.Float: kind = SyntaxKind.NumericLiteralExpression; literalToken = Literal(GetRandomFloat()); break; diff --git a/Program.cs b/Program.cs index 2603265..e3a2d75 100644 --- a/Program.cs +++ b/Program.cs @@ -6,7 +6,7 @@ class Program { static void Main(string[] args) { - PRNG.Initialize(-1); + PRNG.Initialize(5); int testId = 1; while (true) @@ -14,7 +14,7 @@ static void Main(string[] args) TestCase testCase = new TestCase(testId++); testCase.Generate(); testCase.CompileAndExecute(); - } + } } } } diff --git a/TestMethod.cs b/TestMethod.cs index 7074afd..ce7ea07 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -93,7 +93,7 @@ public MethodDeclarationSyntax Generate() methodBody.Add( LocalDeclarationStatement( Helpers.GetVariableDeclaration( - Tree.ValueType.ForPrimitive(Primitive.Int32), + Tree.ValueType.ForPrimitive(Primitive.Int), Constants.LoopInvariantName, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10)))))); @@ -218,7 +218,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) if (assignOper.HasFlag(OpFlags.Shift)) { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int32); + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } else { @@ -232,7 +232,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) { rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, rhs); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); } return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); @@ -243,7 +243,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) ForStatement forStmt = new ForStatement(TC); //TODO:config int n = 3; // max statements - forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int32)); + forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); forStmt.NestNum = depth; forStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -257,8 +257,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PushScope(forLoopScope); - forStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); - forStmt.LoopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int32), Tree.ValueType.ForPrimitive(Primitive.Int32), 0); + forStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); + forStmt.LoopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack @@ -381,7 +381,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i if (op.HasFlag(OpFlags.Shift)) { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int32); + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } ExprKind lhsExprKind, rhsExprKind; @@ -401,7 +401,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i // errors during compiling the test case. if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) { - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); } //TODO-config: Add MaxDepth in config @@ -412,10 +412,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) { rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, rhs); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, exprType, rhs); } - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); + return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); default: Debug.Assert(false, string.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); diff --git a/Tree/Types.cs b/Tree/Types.cs index 8c3f0fb..46136a1 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -28,22 +28,22 @@ public enum Primitive : ulong Char = 0x4, Decimal = 0x8, Double = 0x10, - Int16 = 0x20, - Int32 = 0x40, - Int64 = 0x80, + Short = 0x20, + Int = 0x40, + Long = 0x80, SByte = 0x100, - Single = 0x200, + Float = 0x200, String = 0x400, - UInt16 = 0x800, - UInt32 = 0x1000, - UInt64 = 0x2000, + UShort = 0x800, + UInt = 0x1000, + ULong = 0x2000, Struct = 0x4000, - Numeric = Byte | Decimal | Double | Int16 | Int32 | Int64 | SByte | Single | UInt16 | UInt32 | UInt64, - SignedInteger = SByte | Int16 | Int32 | Int64, - UnsignedInteger = Byte | UInt16 | UInt32 | UInt64, + Numeric = Byte | Decimal | Double | Short | Int | Long | SByte | Float | UShort | UInt | ULong, + SignedInteger = SByte | Short | Int | Long, + UnsignedInteger = Byte | UShort | UInt | ULong, Integer = SignedInteger | UnsignedInteger, - FloatingPoint = Single | Double | Decimal, + FloatingPoint = Float | Double | Decimal, Any = Numeric | Char | String | Boolean, } @@ -79,15 +79,89 @@ public string TypeName new ValueType(Primitive.Char, SpecialType.System_Char, SyntaxKind.CharKeyword), new ValueType(Primitive.Decimal, SpecialType.System_Decimal, SyntaxKind.DecimalKeyword), new ValueType(Primitive.Double, SpecialType.System_Double, SyntaxKind.DoubleKeyword), - new ValueType(Primitive.Int16, SpecialType.System_Int16, SyntaxKind.ShortKeyword), - new ValueType(Primitive.Int32, SpecialType.System_Int32, SyntaxKind.IntKeyword), - new ValueType(Primitive.Int64, SpecialType.System_Int64, SyntaxKind.LongKeyword), + new ValueType(Primitive.Short, SpecialType.System_Int16, SyntaxKind.ShortKeyword), + new ValueType(Primitive.Int, SpecialType.System_Int32, SyntaxKind.IntKeyword), + new ValueType(Primitive.Long, SpecialType.System_Int64, SyntaxKind.LongKeyword), new ValueType(Primitive.SByte, SpecialType.System_SByte, SyntaxKind.SByteKeyword), - new ValueType(Primitive.Single, SpecialType.System_Single, SyntaxKind.FloatKeyword), + new ValueType(Primitive.Float, SpecialType.System_Single, SyntaxKind.FloatKeyword), new ValueType(Primitive.String, SpecialType.System_String, SyntaxKind.StringKeyword), - new ValueType(Primitive.UInt16, SpecialType.System_UInt16, SyntaxKind.UShortKeyword), - new ValueType(Primitive.UInt32, SpecialType.System_UInt32, SyntaxKind.UIntKeyword), - new ValueType(Primitive.UInt64, SpecialType.System_UInt64, SyntaxKind.ULongKeyword), + new ValueType(Primitive.UShort, SpecialType.System_UInt16, SyntaxKind.UShortKeyword), + new ValueType(Primitive.UInt, SpecialType.System_UInt32, SyntaxKind.UIntKeyword), + new ValueType(Primitive.ULong, SpecialType.System_UInt64, SyntaxKind.ULongKeyword), + }; + + /// + /// Returns true if this ValueType can be converted to implicitely. + /// + public bool CanConvertImplicit(ValueType toType) + { + if (PrimitiveType == toType.PrimitiveType) + { + return true; + } + + List toTypes = null; + if (!implicitConversions.TryGetValue(this.PrimitiveType, out toTypes)) + { + return false; + } + return toTypes.Contains(toType.PrimitiveType); + } + + /// + /// Returns true if this ValueType can be converted to explicitely. + /// + public bool CanConvertExplicit(ValueType toType) + { + if (PrimitiveType == toType.PrimitiveType) + { + // if fromType and toType are same, no need of explicit convert + return false; + } + + List toTypes = null; + if (!explicitConversions.TryGetValue(this.PrimitiveType, out toTypes)) + { + return false; + } + return toTypes.Contains(toType.PrimitiveType); + } + + /// + /// Returns true if this ValueType can be converted to implicitely or explicitely. + /// + public bool CanConvert(ValueType toType) + { + return CanConvertImplicit(toType) || CanConvertExplicit(toType); + } + + // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions + private static readonly Dictionary> implicitConversions = new Dictionary>() + { + {Primitive.SByte, new () { Primitive.Short, Primitive.Int, Primitive.Long, Primitive.Float, Primitive.Double, Primitive.Decimal } }, + {Primitive.Byte, new () { Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.Long, Primitive.ULong, Primitive.Float, Primitive.Double, Primitive.Decimal } }, + {Primitive.Short, new () { Primitive.Int, Primitive.Long, Primitive.Float, Primitive.Double, Primitive.Decimal } }, + {Primitive.UShort, new () { Primitive.Int, Primitive.UInt, Primitive.Long, Primitive.ULong, Primitive.Float, Primitive.Double, Primitive.Decimal} }, + {Primitive.Int, new () { Primitive.Long, Primitive.Float, Primitive.Double, Primitive.Decimal } }, + {Primitive.UInt, new () { Primitive.Long, Primitive.ULong, Primitive.Float, Primitive.Double, Primitive.Decimal } }, + {Primitive.Long, new () { Primitive.Float, Primitive.Double, Primitive.Decimal} }, + {Primitive.Float, new () { Primitive.Double} }, + }; + + // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions + private static readonly Dictionary> explicitConversions = new Dictionary>() + { + {Primitive.SByte, new () { Primitive.Byte, Primitive.UShort, Primitive.UInt, Primitive.ULong } }, + {Primitive.Byte, new () { Primitive.SByte } }, + {Primitive.Short, new () { Primitive.SByte, Primitive.Byte, Primitive.UShort, Primitive.UInt, Primitive.ULong} }, + {Primitive.UShort, new () { Primitive.SByte, Primitive.Byte, Primitive.Short} }, + {Primitive.Int, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.UInt, Primitive.ULong} }, + {Primitive.UInt, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int} }, + {Primitive.Long, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.ULong } }, + {Primitive.ULong, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.Long } }, + {Primitive.Float, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.Long, Primitive.ULong, Primitive.Decimal } }, + {Primitive.Double, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.Long, Primitive.ULong, Primitive.Float, Primitive.Decimal } }, + {Primitive.Decimal, new () { Primitive.SByte, Primitive.Byte, Primitive.Short, Primitive.UShort, Primitive.Int, Primitive.UInt, Primitive.Long, Primitive.ULong, Primitive.Float, Primitive.Double } }, }; public static ValueType CreateStructType(string typeName) @@ -119,6 +193,16 @@ public override bool Equals(object obj) _structTypeName == otherType._structTypeName; } + public override int GetHashCode() + { + int hashCode = PrimitiveType.GetHashCode() ^ DataType.GetHashCode() ^ TypeKind.GetHashCode(); + if (_structTypeName != null) + { + hashCode ^= _structTypeName.GetHashCode(); + } + return hashCode; + } + public static ValueType ForPrimitive(Primitive primitiveType) { return types.First(t => t.PrimitiveType == primitiveType); From 13457725ce6ea0b14b065edd0f19fa1ecd818e09 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 3 Jan 2021 22:12:36 -0800 Subject: [PATCH 018/149] Use CoreRun.exe to Verify --- Config/ConfigOptions.cs | 8 +- Config/RunOptions.cs | 16 +++- Program.cs | 15 ++- RoslynTypes.cs | 15 ++- TestCase.cs | 199 ++++++++++++++++++++++++++++++++-------- TestClass.cs | 3 +- TestMethod.cs | 1 + Tree/AstUtils.cs | 1 + 8 files changed, 208 insertions(+), 50 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 23acc8e..9f876de 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -1,9 +1,12 @@ using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; using System; +using System.Diagnostics; +using System.IO; using System.Reflection; +using System.Xml; -namespace Antigen +namespace Antigen.Config { public class OptionsBase { @@ -109,6 +112,9 @@ public class ConfigOptions : OptionsBase // This is a quick fix for now. We need to come up with a better solution for this for IE11. public bool AllowLoopCondAtEnd = false; + // number of testcases to create + public long NumTestCases = 1; + public double Lookup(Tree.ValueType type) { diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index 7bde936..0eaf062 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -1,12 +1,24 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Antigen +namespace Antigen.Config { - public class RunOptions + public class RunOptions : OptionsBase { + // random seed + public int Seed = -1; + + // sets the output directory for tests + public string OutputDirectory = "." + Path.DirectorySeparatorChar; + + // Total number of test cases (overrides number specified in each XML config file) + public long NumTestCases = 0; + + // Duration to execute tests for (overrides number specified in each XML config file) + public ulong SecondsToRun = 0; } } diff --git a/Program.cs b/Program.cs index e3a2d75..e22dabc 100644 --- a/Program.cs +++ b/Program.cs @@ -1,20 +1,27 @@ using System; +using System.Diagnostics; +using Antigen.Config; namespace Antigen { class Program { + + public static RunOptions RunOptions = new RunOptions(); + static void Main(string[] args) { - PRNG.Initialize(5); + PRNG.Initialize(RunOptions.Seed); int testId = 1; while (true) { - TestCase testCase = new TestCase(testId++); + TestCase testCase = new TestCase(testId, RunOptions); testCase.Generate(); - testCase.CompileAndExecute(); - } + TestResult result = testCase.Verify(); + Console.WriteLine($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}"); + testId++; + } } } } diff --git a/RoslynTypes.cs b/RoslynTypes.cs index 4fde9e7..f846008 100644 --- a/RoslynTypes.cs +++ b/RoslynTypes.cs @@ -12,9 +12,18 @@ namespace Antigen { public class Rsln { - internal static SyntaxGenerator synGen = SyntaxGenerator.GetGenerator(new AdhocWorkspace(), LanguageNames.CSharp); - internal static readonly CSharpCompilationOptions DebugOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Debug); - internal static readonly CSharpCompilationOptions ReleaseOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release); + internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); + internal static readonly Dictionary BaselineEnvVars = new Dictionary() + { + { "COMPlus_JITMinOpts", "1" }, + { "COMPlus_TieredCompilation" , "0" } + }; + + internal static readonly Dictionary TestEnvVars = new Dictionary() + { + { "COMPlus_JITMinOpts", "0" }, + { "COMPlus_TieredCompilation" , "0" } + }; } } diff --git a/TestCase.cs b/TestCase.cs index 9e5acc9..f5a1d19 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -1,4 +1,5 @@ -using Antigen.Tree; +using Antigen.Config; +using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -6,15 +7,25 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen { + public enum TestResult + { + CompileError, + OutputMismatch, + Fail, + Pass + } + public class TestCase { #region Compiler options @@ -30,19 +41,26 @@ public enum CompilationType #endregion private const string MainMethodName = "Main"; + private List knownDiffs = new List() + { + "System.OverflowException: Value was either too large or too small for a Decimal.", + "System.DivideByZeroException: Attempted to divide by zero.", + }; - private SyntaxNode testCase; + private SyntaxNode testCaseRoot; //private List classesList; //private List methodsList; //private List propertiesList; //private List fieldsList; + private static RunOptions RunOptions; public string Name { get; private set; } public AstUtils AstUtils { get; private set; } - public TestCase(int testId) + public TestCase(int testId, RunOptions runOptions) { + RunOptions = runOptions; AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; } @@ -63,15 +81,96 @@ public void Generate() ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); - testCase = CompilationUnit() + testCaseRoot = CompilationUnit() .WithUsings(SingletonList(usingDirective)) .WithMembers(new SyntaxList(klass)).NormalizeWhitespace(); } - public void CompileAndExecute() + public TestResult Verify() { - CompileResult compileResult = Compile(CompilationType.Release); - Execute(compileResult); + StringBuilder fileContents = new StringBuilder(); + CompileResult compileResult = Compile(); + if (compileResult.AssemblyFullPath == null) + { + fileContents.AppendLine(testCaseRoot.ToFullString()); + fileContents.AppendLine("/*"); + fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); + foreach (var error in compileResult.CompileErrors) + { + fileContents.AppendLine(error.ToString()); + } + fileContents.AppendLine("*/"); + + string errorFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); + File.WriteAllText(errorFile, fileContents.ToString()); + + return TestResult.CompileError; + } + + string baseline = Execute(compileResult, Rsln.BaselineEnvVars); + string test = Execute(compileResult, Rsln.TestEnvVars); + + if (baseline == test) + { + try + { + File.Delete(compileResult.AssemblyFullPath); + } + catch (Exception) + { + // ignore errors + } + return TestResult.Pass; + } + + bool isKnownError = false; + foreach (string knownError in knownDiffs) + { + if (baseline.Contains(knownError) && test.Contains(knownError)) + { + isKnownError = true; + break; + } + } + + fileContents.AppendLine(testCaseRoot.ToFullString()); + fileContents.AppendLine("/*"); + if (isKnownError) + { + fileContents.AppendLine($"Got known error mismatch:"); + } + else + { + fileContents.AppendLine($"Got output diff:"); + } + fileContents.AppendLine("--------- Baseline --------- "); + fileContents.AppendLine(baseline); + fileContents.AppendLine("--------- Test --------- "); + fileContents.AppendLine(test); + fileContents.AppendLine("*/"); + + //TODO- for now, delete known error files + if (!isKnownError) + { + string failedFileName = $"{Name}-{(isKnownError ? "known-error" : "fail")}"; + string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); + File.WriteAllText(failFile, fileContents.ToString()); + + File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); + return TestResult.Fail; + } + else + { + try + { + File.Delete(compileResult.AssemblyFullPath); + } + catch (Exception) + { + // ignore errors + } + return TestResult.OutputMismatch; + } } /// @@ -108,27 +207,21 @@ private void FindDiff(SyntaxNode expected, SyntaxNode actual) } } - private CompileResult Compile(CompilationType compilationType) + /// + /// Compiles the generated . + /// + /// + private CompileResult Compile() { - string testCaseContents = testCase.ToFullString(); - File.WriteAllText(@$"E:\git\Antigen\{Name}.g.cs", testCaseContents); - - string[] testCaseCode = testCaseContents.Split(Environment.NewLine); - int lineNum = 1; - foreach (string code in testCaseCode) - { - Console.WriteLine("[{0,4:D4}]{1}", lineNum++, code); - } - #if DEBUG - SyntaxTree syntaxTree = testCase.SyntaxTree; - SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCase.ToFullString()); + SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; + SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); FindDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); #else // In release, make sure that we didn't end up generating wrong syntax tree, // hence parse the text to reconstruct the tree. - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCase.ToFullString()); + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); #endif string corelibPath = typeof(object).Assembly.Location; @@ -141,7 +234,8 @@ private CompileResult Compile(CompilationType compilationType) MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - var cc = CSharpCompilation.Create(Name, new SyntaxTree[] { syntaxTree }, references, compilationType == CompilationType.Debug ? Rsln.DebugOptions : Rsln.ReleaseOptions); + var cc = CSharpCompilation.Create($"{Name}.exe", new SyntaxTree[] { syntaxTree }, references, Rsln.CompileOptions); + string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{Name}.exe"); using (var ms = new MemoryStream()) { @@ -159,22 +253,24 @@ private CompileResult Compile(CompilationType compilationType) if (!result.Success) return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null); - return new CompileResult(null, ImmutableArray.Empty, ms.ToArray()); + ms.Seek(0, SeekOrigin.Begin); + File.WriteAllBytes(assemblyFullPath, ms.ToArray()); + + return new CompileResult(null, ImmutableArray.Empty, assemblyFullPath); } } - private delegate void MainMethodInvoke(); - private void Execute(CompileResult compileResult) + /// + /// Execute the compiled assembly in an environment that has . + /// + /// + private string Execute(CompileResult compileResult, Dictionary environmentVariables) { - if (compileResult.Assembly == null) - { - Console.WriteLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); - Console.WriteLine(string.Join(Environment.NewLine, compileResult.CompileErrors)); - Console.ReadLine(); - } - else + Debug.Assert(compileResult.AssemblyFullPath != null); + if (false) { - Assembly asm = Assembly.Load(compileResult.Assembly); + //TODO: if execute in debug vs. release dotnet.exe + Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); Type testClassType = asm.GetType(Name); MethodInfo mainMethodInfo = testClassType.GetMethod(MainMethodName); Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); @@ -201,16 +297,41 @@ private void Execute(CompileResult compileResult) sw.Close(); } - string stdout = Encoding.UTF8.GetString(ms.ToArray()); - Console.WriteLine(stdout); - Console.ReadLine(); + return Encoding.UTF8.GetString(ms.ToArray()); + } + else + { + ProcessStartInfo info = new ProcessStartInfo + { + FileName = /*@"C:\git\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\CoreRun.exe", */@"D:\git\runtime\artifacts\tests\coreclr\windows.x64.Checked\tests\Core_Root\CoreRun.exe", + Arguments = compileResult.AssemblyFullPath, + WorkingDirectory = Environment.CurrentDirectory, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + }; + + foreach (var envVar in environmentVariables) + { + info.EnvironmentVariables[envVar.Key] = envVar.Value; + } + + using (Process proc = Process.Start(info)) + { + string results = proc.StandardOutput.ReadToEnd(); + results += proc.StandardError.ReadToEnd(); + proc.WaitForExit(1 * 60 * 1000); // 1 minute + + return results; + } } } } internal class CompileResult { - public CompileResult(Exception roslynException, ImmutableArray diagnostics, byte[] assembly) + public CompileResult(Exception roslynException, ImmutableArray diagnostics, string assemblyFullPath) { RoslynException = roslynException; List errors = new List(); @@ -228,12 +349,12 @@ public CompileResult(Exception roslynException, ImmutableArray diagn } CompileErrors = errors.ToImmutableArray(); CompileWarnings = warnings.ToImmutableArray(); - Assembly = assembly; + AssemblyFullPath = assemblyFullPath; } public Exception RoslynException { get; } public ImmutableArray CompileErrors { get; } public ImmutableArray CompileWarnings { get; } - public byte[] Assembly { get; } + public string AssemblyFullPath { get; } } } diff --git a/TestClass.cs b/TestClass.cs index 302ae51..4bcbbb8 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -69,7 +69,8 @@ public ClassDeclarationSyntax Generate() PopScope(); return ClassDeclaration(ClassName) - .WithMembers(new SyntaxList(classMembers)); + .WithMembers(new SyntaxList(classMembers)) + .WithModifiers(new SyntaxTokenList(Token(SyntaxKind.PublicKeyword))); } /// diff --git a/TestMethod.cs b/TestMethod.cs index ce7ea07..89d3a19 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -97,6 +97,7 @@ public MethodDeclarationSyntax Generate() Constants.LoopInvariantName, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10)))))); + //TODO-config: Statements in a function for (int i = 0; i < 10; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 13357d8..59925cc 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Antigen.Config; using Antigen.Statements; namespace Antigen.Tree From f5c554171570021c05ac764c10bfe270b0314bcd Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 3 Jan 2021 22:36:27 -0800 Subject: [PATCH 019/149] wip: Function call --- Config/ConfigOptions.cs | 1 + TestClass.cs | 54 +++++++++++++++++++++++++++++++++++++++++ TestMethod.cs | 1 + Tree/Expressions.cs | 1 + Tree/Statements.cs | 1 + 5 files changed, 58 insertions(+) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 9f876de..7b3718b 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -20,6 +20,7 @@ public class ConfigOptions : OptionsBase public double LiteralWeight = 0.025; public double VariableWeight = 0.5; public double BinaryOpWeight = 1; + public double FunctionCallWeight = 0.5; // Statement weights public double VariableDeclarationWeight = 0.5; diff --git a/TestClass.cs b/TestClass.cs index 4bcbbb8..04f11c6 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -26,6 +26,58 @@ public class TestClass public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } + /// + /// Map of caller to list of callees. + /// + private Dictionary> _callerToCalleesMap; + + internal bool CanCallRecurse(string fromMethod, string toMethod) + { + + // if toMethod is not a caller, then there shouldn't be any recursion. + //if (!_callerToCalleesMap.ContainsKey(toMethod)) + //{ + // return false; + //} + + //HashSet visited = new HashSet() { toMethod }; + //HashSet callees = _callerToCalleesMap[toMethod]; + //int calleeCount = callees.Count; + //for (int i = 0; i < calleeCount; i++) + //{ + // HashSet newCallees = new HashSet(); + + // if (!_callerToCalleesMap.ContainsKey(toMethod)) + // { + // return false; + // } + + // var currCallees = _callerToCalleesMap[toMethod]; + // foreach (var callee in currCallees) + // { + // if (visited.Add(callee)) + // { + // newCallees.Add(callee); + // } + // } + + //} + + //while (callees.Count > 0) + //{ + // HashSet newCallees = new HashSet(); + + // if (!_callerToCalleesMap.ContainsKey(toMethod)) + // { + // return false; + // } + + // var callees = _callerToCalleesMap[toMethod]; + + //} + return false; + } + public AstUtils GetASTUtils() { return TC.AstUtils; @@ -37,6 +89,7 @@ public TestClass(TestCase tc, string className) ClassScope = new Scope(tc); ClassName = className; TC = tc; + _callerToCalleesMap = new Dictionary>(); } public Scope CurrentScope @@ -158,6 +211,7 @@ private IList GenerateMethods() { var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); + _callerToCalleesMap["Method" + i] = testMethod.callsFromThisMethod; } return methods; diff --git a/TestMethod.cs b/TestMethod.cs index 89d3a19..d47ad68 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -25,6 +25,7 @@ public class TestMethod #endif private int variablesCount = 0; + internal HashSet callsFromThisMethod = new HashSet(); public AstUtils GetASTUtils() { diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index 8973827..08d5f11 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -5,6 +5,7 @@ public enum ExprKind LiteralExpression, VariableExpression, BinaryOpExpression, + //FunctionCallExpression, } //public struct Expression diff --git a/Tree/Statements.cs b/Tree/Statements.cs index f8463d1..42cfcda 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -8,6 +8,7 @@ public enum StmtKind ForStatement, DoWhileStatement, WhileStatement, + //FunctionCallStatement, } //public class Statements From fcdfd700308f39a936c8f5032704bf01e9cd9ae3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 3 Jan 2021 22:37:02 -0800 Subject: [PATCH 020/149] Add COMPlus_* variables --- RoslynTypes.cs | 112 ++++++++++++++++++++++++++++++++++++++++++++++++- TestCase.cs | 27 +++++++++++- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/RoslynTypes.cs b/RoslynTypes.cs index f846008..4ac94c8 100644 --- a/RoslynTypes.cs +++ b/RoslynTypes.cs @@ -20,10 +20,120 @@ public class Rsln { "COMPlus_TieredCompilation" , "0" } }; - internal static readonly Dictionary TestEnvVars = new Dictionary() + internal static readonly Dictionary CommonTestEnvVars = new Dictionary() { { "COMPlus_JITMinOpts", "0" }, { "COMPlus_TieredCompilation" , "0" } }; + + // Use other combination from https://github.com/dotnet/runtime/blob/5a6c21cb6285a3c110f0048d9bf657042ea4ca10/src/tests/Common/testenvironment.proj + // groups / arch: https://github.com/dotnet/runtime/blob/f8a83c898f18e3ebcd7c0ddd2e1773d8a771b346/eng/pipelines/common/templates/runtimes/run-test-job.yml + internal static readonly List TestEnvVars = new List() + { + new ComplusVariableGroup("jitstress1", new () + { + { "COMPlus_JitStress", "1" }, + }), + new ComplusVariableGroup("jitstress1_tiered", new () + { + { "COMPlus_JitStress", "1" }, + { "COMPlus_TieredCompilation", "1" }, + }), + new ComplusVariableGroup("jitstress2", new () + { + { "COMPlus_JitStress", "2" }, + }), + new ComplusVariableGroup("jitstress2_tiered", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_TieredCompilation", "1" }, + }), + new ComplusVariableGroup("jitstressregs1", new () + { + { "COMPlus_JitStressRegs", "1" }, + }), + new ComplusVariableGroup("jitstressregs2", new () + { + { "COMPlus_JitStressRegs", "2" }, + }), + new ComplusVariableGroup("jitstressregs3", new () + { + { "COMPlus_JitStressRegs", "3" }, + }), + new ComplusVariableGroup("jitstressregs4", new () + { + { "COMPlus_JitStressRegs", "4" }, + }), + new ComplusVariableGroup("jitstressregs8", new () + { + { "COMPlus_JitStressRegs", "8" }, + }), + new ComplusVariableGroup("jitstressregs10", new () + { + { "COMPlus_JitStressRegs", "0x10" }, + }), + new ComplusVariableGroup("jitstressregs80", new () + { + { "COMPlus_JitStressRegs", "0x80" }, + }), + new ComplusVariableGroup("jitstressregs1000", new () + { + { "COMPlus_JitStressRegs", "0x10000" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs1", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "1" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs2", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "2" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs3", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "3" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs4", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "4" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs8", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "8" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs0x10", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "0x10" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs0x80", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "0x80" }, + }), + new ComplusVariableGroup("jitstress2_jitstressregs0x1000", new () + { + { "COMPlus_JitStress", "2" }, + { "COMPlus_JitStressRegs", "0x10000" }, + }), + }; + } + + public class ComplusVariableGroup + { + public string Name { get; private set; } + public Dictionary Vars { get; set; } + + internal ComplusVariableGroup(string name, Dictionary vars) + { + Name = name; + Vars = vars; + } } + + } diff --git a/TestCase.cs b/TestCase.cs index f5a1d19..0eced4f 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -108,7 +108,20 @@ public TestResult Verify() } string baseline = Execute(compileResult, Rsln.BaselineEnvVars); - string test = Execute(compileResult, Rsln.TestEnvVars); + + var selectedVars = Rsln.TestEnvVars[PRNG.Next(Rsln.TestEnvVars.Count)].Vars; + var testEnvVariables = new Dictionary(); + foreach (var commonVars in Rsln.CommonTestEnvVars) + { + testEnvVariables.Add(commonVars.Key, commonVars.Value); + } + foreach (var selectedVar in selectedVars) + { + // override the COMPlus_TieredCompilation variable + testEnvVariables[selectedVar.Key] = selectedVar.Value; + } + + string test = Execute(compileResult, testEnvVariables); if (baseline == test) { @@ -135,6 +148,18 @@ public TestResult Verify() fileContents.AppendLine(testCaseRoot.ToFullString()); fileContents.AppendLine("/*"); + + fileContents.AppendLine("Baseline environment:"); + foreach (var envVars in Rsln.BaselineEnvVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine("Test environment:"); + foreach (var envVars in testEnvVariables) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + if (isKnownError) { fileContents.AppendLine($"Got known error mismatch:"); From f8e8e4684888c82b54782b5d0f353c8ad9ce3aba Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 4 Jan 2021 07:12:49 -0800 Subject: [PATCH 021/149] Option to pass CoreRun.exe --- Config/RunOptions.cs | 3 +++ Program.cs | 2 ++ TestCase.cs | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index 0eaf062..10c0f5f 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -20,5 +20,8 @@ public class RunOptions : OptionsBase // Duration to execute tests for (overrides number specified in each XML config file) public ulong SecondsToRun = 0; + + // Full path to CoreRun.exe + public string CoreRun = null; } } diff --git a/Program.cs b/Program.cs index e22dabc..b350971 100644 --- a/Program.cs +++ b/Program.cs @@ -13,6 +13,8 @@ static void Main(string[] args) { PRNG.Initialize(RunOptions.Seed); + RunOptions.CoreRun = args[0]; + int testId = 1; while (true) { diff --git a/TestCase.cs b/TestCase.cs index 0eced4f..1c57f01 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -328,7 +328,7 @@ private string Execute(CompileResult compileResult, Dictionary e { ProcessStartInfo info = new ProcessStartInfo { - FileName = /*@"C:\git\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\CoreRun.exe", */@"D:\git\runtime\artifacts\tests\coreclr\windows.x64.Checked\tests\Core_Root\CoreRun.exe", + FileName = RunOptions.CoreRun, Arguments = compileResult.AssemblyFullPath, WorkingDirectory = Environment.CurrentDirectory, RedirectStandardOutput = true, From f88efd2ff3aa3dbb01f28f9570f7e0c2e1de10dc Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 5 Jan 2021 00:21:32 -0800 Subject: [PATCH 022/149] Method signature --- Helpers/VariableDeclarationHelper.cs | 34 +++++ Program.cs | 19 ++- TestCase.cs | 34 ++--- TestClass.cs | 69 +++-------- TestMethod.cs | 178 +++++++++++++++++++++++++-- Tree/Expressions.cs | 1 - Tree/Types.cs | 6 + 7 files changed, 258 insertions(+), 83 deletions(-) diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs index 5b6eda2..a3fce93 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Helpers/VariableDeclarationHelper.cs @@ -117,5 +117,39 @@ public static ObjectCreationExpressionSyntax GetObjectCreationExpression(string return ObjectCreationExpression(objectTypeSyntax).WithArgumentList( ArgumentList()); } + + //TODO: Reuse in GetVariableDeclaration + public static ParameterSyntax GetParameterSyntax(Tree.ValueType variableType, string variableName) + { + ParameterSyntax parameterSyntax = Parameter(Identifier(variableName)); + return parameterSyntax.WithType(GetTypeSyntax(variableType)); + } + + //TODO: Reuse in GetVariableDeclaration + public static TypeSyntax GetTypeSyntax(Tree.ValueType variableType) + { + if (variableType.PrimitiveType == Primitive.Struct) + { + if (!variableType.TypeName.Contains(".")) + { + return IdentifierName(variableType.TypeName); + } + + // contains nested struct + string[] seperatedTypes = variableType.TypeName.Split('.', StringSplitOptions.RemoveEmptyEntries); + NameSyntax nameSyntax = QualifiedName( + IdentifierName(seperatedTypes[0]), + IdentifierName(seperatedTypes[1])); + for (int subType = 2; subType < seperatedTypes.Length; subType++) + { + nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); + } + return nameSyntax; + } + else + { + return GetToken(variableType.TypeKind); + } + } } } diff --git a/Program.cs b/Program.cs index b350971..8b8497b 100644 --- a/Program.cs +++ b/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using Antigen.Config; @@ -16,12 +17,28 @@ static void Main(string[] args) RunOptions.CoreRun = args[0]; int testId = 1; + Dictionary stats = new Dictionary() + { + { TestResult.CompileError, 0 }, + { TestResult.Fail, 0 }, + {TestResult.OutputMismatch, 0 }, + {TestResult.Pass, 0 }, + }; while (true) { TestCase testCase = new TestCase(testId, RunOptions); testCase.Generate(); TestResult result = testCase.Verify(); - Console.WriteLine($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}"); + stats[result]++; + Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. "); + if ((testId % 100) == 0) + { + foreach (var st in stats) + { + Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); + } + } + Console.WriteLine(); testId++; } } diff --git a/TestCase.cs b/TestCase.cs index 1c57f01..7853ec3 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -149,17 +149,6 @@ public TestResult Verify() fileContents.AppendLine(testCaseRoot.ToFullString()); fileContents.AppendLine("/*"); - fileContents.AppendLine("Baseline environment:"); - foreach (var envVars in Rsln.BaselineEnvVars) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - fileContents.AppendLine("Test environment:"); - foreach (var envVars in testEnvVariables) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - if (isKnownError) { fileContents.AppendLine($"Got known error mismatch:"); @@ -169,8 +158,25 @@ public TestResult Verify() fileContents.AppendLine($"Got output diff:"); } fileContents.AppendLine("--------- Baseline --------- "); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in Rsln.BaselineEnvVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); fileContents.AppendLine(baseline); + fileContents.AppendLine("--------- Test --------- "); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in testEnvVariables) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); fileContents.AppendLine(test); fileContents.AppendLine("*/"); @@ -204,7 +210,7 @@ public TestResult Verify() /// /// /// - private void FindDiff(SyntaxNode expected, SyntaxNode actual) + private void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) { if ((expected is LiteralExpressionSyntax) || (actual is LiteralExpressionSyntax)) { @@ -226,7 +232,7 @@ private void FindDiff(SyntaxNode expected, SyntaxNode actual) } for (int ch = 0; ch < expectedCount; ch++) { - FindDiff(expectedChildNodes[ch], actualChildNodes[ch]); + FindTreeDiff(expectedChildNodes[ch], actualChildNodes[ch]); } return; } @@ -241,7 +247,7 @@ private CompileResult Compile() #if DEBUG SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); - FindDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); + FindTreeDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); #else // In release, make sure that we didn't end up generating wrong syntax tree, // hence parse the text to reconstruct the tree. diff --git a/TestClass.cs b/TestClass.cs index 04f11c6..13e6e4f 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -25,58 +25,7 @@ public class TestClass public string ClassName; public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } - - /// - /// Map of caller to list of callees. - /// - private Dictionary> _callerToCalleesMap; - - internal bool CanCallRecurse(string fromMethod, string toMethod) - { - - // if toMethod is not a caller, then there shouldn't be any recursion. - //if (!_callerToCalleesMap.ContainsKey(toMethod)) - //{ - // return false; - //} - - //HashSet visited = new HashSet() { toMethod }; - //HashSet callees = _callerToCalleesMap[toMethod]; - //int calleeCount = callees.Count; - //for (int i = 0; i < calleeCount; i++) - //{ - // HashSet newCallees = new HashSet(); - - // if (!_callerToCalleesMap.ContainsKey(toMethod)) - // { - // return false; - // } - - // var currCallees = _callerToCalleesMap[toMethod]; - // foreach (var callee in currCallees) - // { - // if (visited.Add(callee)) - // { - // newCallees.Add(callee); - // } - // } - - //} - - //while (callees.Count > 0) - //{ - // HashSet newCallees = new HashSet(); - - // if (!_callerToCalleesMap.ContainsKey(toMethod)) - // { - // return false; - // } - - // var callees = _callerToCalleesMap[toMethod]; - - //} - return false; - } + public List Methods { get; private set; } public AstUtils GetASTUtils() { @@ -89,7 +38,17 @@ public TestClass(TestCase tc, string className) ClassScope = new Scope(tc); ClassName = className; TC = tc; - _callerToCalleesMap = new Dictionary>(); + Methods = new List(); + } + + public void RegisterMethod(MethodSignature methodSignature) + { + Methods.Add(methodSignature); + } + + public MethodSignature GetRandomMethod() + { + return Methods[PRNG.Next(Methods.Count)]; } public Scope CurrentScope @@ -205,13 +164,13 @@ private IList GenerateMethods() obj{ClassName}.Method0(); }} ")); + methods.Add(new TestMethod(this, "Method0", false).Generate()); //TODO-config: No. of methods per class - for (int i = 0; i < 1; i++) + for (int i = 1; i < 5; i++) { var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); - _callerToCalleesMap["Method" + i] = testMethod.callsFromThisMethod; } return methods; diff --git a/TestMethod.cs b/TestMethod.cs index d47ad68..dd09020 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.VisualBasic.CompilerServices; using System; using System.Collections.Generic; using System.Diagnostics; @@ -33,6 +34,8 @@ public AstUtils GetASTUtils() } private Scope MethodScope; + private bool takesParameters; + public MethodSignature MethodSignature { get; private set; } public Scope CurrentScope => testClass.CurrentScope; public void PushScope(Scope scope) @@ -47,18 +50,19 @@ public Scope PopScope() return ret; } - public TestMethod(TestClass enclosingClass, string methodName) + public TestMethod(TestClass enclosingClass, string methodName, bool takesParams = true) { testClass = enclosingClass; Name = methodName; MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); + takesParameters = takesParams; } public MethodDeclarationSyntax Generate() { PushScope(MethodScope); - MethodDeclarationSyntax methodDeclaration = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Name).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + MethodDeclarationSyntax methodDeclaration = GenerateMethodSignature(); IList methodBody = new List(); // TODO-TEMP initialize one variable of each type @@ -113,26 +117,93 @@ public MethodDeclarationSyntax Generate() PopScope(); + testClass.RegisterMethod(MethodSignature); + // Wrap everything in unchecked so we do not see overflow compilation errors return methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); } + /// + /// Generates method signature of this method. + /// + private MethodDeclarationSyntax GenerateMethodSignature() + { + MethodSignature = new MethodSignature(Name); + int numOfParameters = 0; + if (takesParameters) + { + //TODO:config - No. of parameters + numOfParameters = PRNG.Next(1, 10); + MethodSignature.ReturnType = GetRandomExprType(); + } + + List parameters = new List(); + MethodSignature.Parameters = parameters; + List parameterNodes = new List(); + + for (int paramIndex = 0; paramIndex < numOfParameters; paramIndex++) + { + var paramType = GetRandomExprType(); + var passingWay = PRNG.WeightedChoice(MethodSignature.ValuePassing); + string paramName = "p_" + Helpers.GetVariableName(paramType, paramIndex); + CurrentScope.AddLocal(paramType, paramName); + + ParameterSyntax parameterNode = Helpers.GetParameterSyntax(paramType, paramName); + if (passingWay != ParamValuePassing.None) + { + SyntaxToken passingWayToken = Token(SyntaxKind.None); + switch (passingWay) + { + case ParamValuePassing.In: + passingWayToken = Token(SyntaxKind.InKeyword); + break; + case ParamValuePassing.Out: + passingWayToken = Token(SyntaxKind.OutKeyword); + break; + case ParamValuePassing.Ref: + passingWayToken = Token(SyntaxKind.RefKeyword); + break; + default: + Debug.Assert(false, "invalid value for passingway!"); + break; + } + parameterNode = parameterNode.WithModifiers(TokenList(passingWayToken)); + } + + parameters.Add(new MethodParam() + { + ParamType = paramType, + PassingWay = passingWay + }); + parameterNodes.Add(parameterNode); + } + + + List finalPametersList = new List(); + + if (takesParameters) + { + finalPametersList.Add(parameterNodes[0]); + } + + for (int paramIndex = 1; paramIndex < numOfParameters; paramIndex++) + { + finalPametersList.Add(Token(SyntaxKind.CommaToken)); + finalPametersList.Add(parameterNodes[paramIndex]); + } + + return MethodDeclaration(Helpers.GetTypeSyntax(MethodSignature.ReturnType), Name) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + .WithParameterList(ParameterList(SeparatedList(finalPametersList))); + } + public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { switch (stmtKind) { case StmtKind.VariableDeclaration: { - Tree.ValueType variableType; - //TODO:config - probability of struct variables - if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) - { - variableType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; - } - else - { - variableType = GetASTUtils().GetRandomExprType(); - } + Tree.ValueType variableType = GetRandomExprType(); string variableName = Helpers.GetVariableName(variableType, variablesCount++); @@ -426,6 +497,18 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return null; } + private Tree.ValueType GetRandomExprType() + { + //TODO:config - probability of struct variables + if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) + { + return CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + } + else + { + return GetASTUtils().GetRandomExprType(); + } + } private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) { @@ -457,4 +540,75 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment) #endif } } + + public class MethodSignature + { + public string MethodName; + public Tree.ValueType ReturnType; + public List Parameters; + + //TODO:config + public static List> ValuePassing = new() + { + new Weights(ParamValuePassing.None, 50), + new Weights(ParamValuePassing.Ref, 25), + new Weights(ParamValuePassing.Out, 15), + new Weights(ParamValuePassing.In, 10), + }; + + public MethodSignature(string methodName) + { + MethodName = methodName; + ReturnType = Tree.ValueType.ForVoid(); + Parameters = new List(); + } + + public override bool Equals(object obj) + { + if (obj is not MethodSignature otherMethodSig) + { + return false; + } + return MethodName == otherMethodSig.MethodName && + (ReturnType.Equals(otherMethodSig.ReturnType)) && + Parameters.Count == otherMethodSig.Parameters.Count && + Enumerable.Range(0, Parameters.Count) + .All(pIndex => (Parameters[pIndex].ParamType.Equals(otherMethodSig.Parameters[pIndex].ParamType) && + (Parameters[pIndex].PassingWay == otherMethodSig.Parameters[pIndex].PassingWay))); + } + + public override int GetHashCode() + { + int hashCode = 0; + foreach (var p in Parameters) + { + hashCode ^= p.ParamType.GetHashCode(); + } + return MethodName.GetHashCode() ^ ReturnType.GetHashCode() ^ hashCode; + } + + public override string ToString() + { + var paramList = Parameters.Select(p => $"{(p.PassingWay == ParamValuePassing.None ? "" : Enum.GetName(typeof(ParamValuePassing), p.PassingWay))} {p.ParamType}"); + return $"{ReturnType} {MethodName}({string.Join(", ", paramList)})"; + } + + } + + public class MethodParam + { + public Tree.ValueType ParamType; + public ParamValuePassing PassingWay; + + //public MethodParam(Tree.ValueType paramType, ParamValuePassing passingWay) + //{ + // ParamType = paramType; + // PassingWay = passi + //} + } + + public enum ParamValuePassing + { + None, In, Out, Ref + }; } diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index 08d5f11..db6e43c 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -10,6 +10,5 @@ public enum ExprKind //public struct Expression //{ - //} } diff --git a/Tree/Types.cs b/Tree/Types.cs index 46136a1..da5877f 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -208,6 +208,12 @@ public static ValueType ForPrimitive(Primitive primitiveType) return types.First(t => t.PrimitiveType == primitiveType); } + private static ValueType voidType = new ValueType(Primitive.Void, SpecialType.System_Void, SyntaxKind.VoidKeyword); + public static ValueType ForVoid() + { + return voidType; + } + public string VariableNameHint() { if (PrimitiveType != Primitive.Struct) From 2c42e8dd13467ed5521e97b04d1ea9384d0687f0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 6 Jan 2021 07:42:03 -0800 Subject: [PATCH 023/149] (x += y) --- Config/ConfigOptions.cs | 1 + README.md | 3 ++- TestMethod.cs | 29 +++++++++++++++++++++++++++++ Tree/AstUtils.cs | 4 ++-- Tree/Expressions.cs | 1 + 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 7b3718b..7ca2046 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -21,6 +21,7 @@ public class ConfigOptions : OptionsBase public double VariableWeight = 0.5; public double BinaryOpWeight = 1; public double FunctionCallWeight = 0.5; + public double AssignWeight = 0.1; // Statement weights public double VariableDeclarationWeight = 0.5; diff --git a/README.md b/README.md index 462b4c0..4fbfe71 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 6. For-loop 7. Do-While loop 8. While loop -9. struct \ No newline at end of file +9. struct +10. Assignment expression \ No newline at end of file diff --git a/TestMethod.cs b/TestMethod.cs index dd09020..b079e8d 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -432,12 +432,17 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i switch (exprKind) { case ExprKind.LiteralExpression: + { return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); + } case ExprKind.VariableExpression: + { return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); + } case ExprKind.BinaryOpExpression: + { Primitive returnType = exprType.PrimitiveType; Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); @@ -489,6 +494,30 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); + } + case ExprKind.AssignExpression: + { + Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(returnPrimitiveType: exprType.PrimitiveType); + Tree.ValueType lhsExprType, rhsExprType; + lhsExprType = rhsExprType = exprType; + + if (assignOper.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + } + + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); + ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + + // For division, make sure that divisor is not 0 + if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) + { + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); + } + + return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); + } default: Debug.Assert(false, string.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 59925cc..960862a 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -195,12 +195,12 @@ where z.Data.HasFlag(OpFlags.Unary) return PRNG.WeightedChoice(ops); } - public Operator GetRandomAssignmentOperator() + public Operator GetRandomAssignmentOperator(Primitive returnPrimitiveType = Primitive.Any) { // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(OpFlags.Assignment) + where z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnPrimitiveType) select z; // Do a weighted random choice. diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index db6e43c..ddb26ef 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -5,6 +5,7 @@ public enum ExprKind LiteralExpression, VariableExpression, BinaryOpExpression, + AssignExpression, //FunctionCallExpression, } From 0289044750b5cbb55d78e7dd569c1c3100658e71 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 6 Jan 2021 08:53:59 -0800 Subject: [PATCH 024/149] initialize out params, return; --- README.md | 3 +- TestCase.cs | 5 ++ TestMethod.cs | 198 ++++++++++++++++++++++++++++++++------------- Tree/AstUtils.cs | 5 ++ Tree/Statements.cs | 1 + 5 files changed, 156 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 4fbfe71..9747821 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 7. Do-While loop 8. While loop 9. struct -10. Assignment expression \ No newline at end of file +10. Assignment expression +11. Initialize out, return statement \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 7853ec3..6fb8bec 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -106,6 +106,11 @@ public TestResult Verify() return TestResult.CompileError; } + //else + //{ + // string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); + // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); + //} string baseline = Execute(compileResult, Rsln.BaselineEnvVars); diff --git a/TestMethod.cs b/TestMethod.cs index b079e8d..de9e6cc 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -102,8 +102,16 @@ public MethodDeclarationSyntax Generate() Constants.LoopInvariantName, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10)))))); + // TODO-TEMP initialize out and ref method parameters + var paramsToInitialize = MethodSignature.Parameters.Where(p => p.PassingWay == ParamValuePassing.Out); + foreach (MethodParam param in paramsToInitialize) + { + methodBody.Add(VariableAssignmentHelper(param.ParamType, param.ParamName)); + CurrentScope.AddLocal(param.ParamType, param.ParamName); + } + //TODO-config: Statements in a function - for (int i = 0; i < 10; i++) + for (int i = 0; i < 5; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); methodBody.Add(StatementHelper(cur, 0)); @@ -115,6 +123,9 @@ public MethodDeclarationSyntax Generate() methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); } + // return statement + methodBody.Add(StatementHelper(StmtKind.ReturnStatement, 0)); + PopScope(); testClass.RegisterMethod(MethodSignature); @@ -146,7 +157,13 @@ private MethodDeclarationSyntax GenerateMethodSignature() var paramType = GetRandomExprType(); var passingWay = PRNG.WeightedChoice(MethodSignature.ValuePassing); string paramName = "p_" + Helpers.GetVariableName(paramType, paramIndex); - CurrentScope.AddLocal(paramType, paramName); + + // Add parameters to the scope except the one that is marked as OUT + // OUT parameters will be added once they are initialized. + if (passingWay != ParamValuePassing.Out) + { + CurrentScope.AddLocal(paramType, paramName); + } ParameterSyntax parameterNode = Helpers.GetParameterSyntax(paramType, paramName); if (passingWay != ParamValuePassing.None) @@ -154,9 +171,9 @@ private MethodDeclarationSyntax GenerateMethodSignature() SyntaxToken passingWayToken = Token(SyntaxKind.None); switch (passingWay) { - case ParamValuePassing.In: - passingWayToken = Token(SyntaxKind.InKeyword); - break; + //case ParamValuePassing.In: + // passingWayToken = Token(SyntaxKind.InKeyword); + // break; case ParamValuePassing.Out: passingWayToken = Token(SyntaxKind.OutKeyword); break; @@ -172,6 +189,7 @@ private MethodDeclarationSyntax GenerateMethodSignature() parameters.Add(new MethodParam() { + ParamName = paramName, ParamType = paramType, PassingWay = passingWay }); @@ -299,7 +317,20 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + ExpressionSyntax rhs = null; + + //TODO-config no. of attempts + int noOfAttempts = 0; + while (noOfAttempts++ < 5) + { + rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + // Make sure that we do not end up with same lhs=lhs. + if (lhs.ToFullString() != rhs.ToFullString()) + { + break; + } + } + Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) @@ -420,6 +451,14 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop while scope return Annotate(Block(whileStmt.Generate(false)), "while-loop"); } + case StmtKind.ReturnStatement: + Tree.ValueType returnType = MethodSignature.ReturnType; + if (returnType.PrimitiveType == Primitive.Void) + { + return Annotate(ReturnStatement(), "Return"); + } + ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); + return Annotate(ReturnStatement(returnExpr), "Return"); default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; @@ -433,67 +472,67 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i { case ExprKind.LiteralExpression: { - return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); + return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); } case ExprKind.VariableExpression: { - return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); + return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); } case ExprKind.BinaryOpExpression: { - Primitive returnType = exprType.PrimitiveType; + Primitive returnType = exprType.PrimitiveType; - Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); + Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); - // If the return type is boolean, then take any ExprType that returns boolean. - // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. - //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, - // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and - // the literals are selected of different type ("decimal" in this example) and we get compilation error - // because they can't be casted to short. - Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); - //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); - Tree.ValueType rhsExprType = lhsExprType; + // If the return type is boolean, then take any ExprType that returns boolean. + // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. + //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, + // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and + // the literals are selected of different type ("decimal" in this example) and we get compilation error + // because they can't be casted to short. + Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); + //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + Tree.ValueType rhsExprType = lhsExprType; - if (op.HasFlag(OpFlags.Shift)) - { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - } + if (op.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + } - ExprKind lhsExprKind, rhsExprKind; - //TODO-config: Add MaxDepth in config - if (depth >= 5) - { - lhsExprKind = rhsExprKind = ExprKind.LiteralExpression; - } - else - { - lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); - rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); - } + ExprKind lhsExprKind, rhsExprKind; + //TODO-config: Add MaxDepth in config + if (depth >= 5) + { + lhsExprKind = rhsExprKind = ExprKind.LiteralExpression; + } + else + { + lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); + rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + } - // Fold arithmetic binop expressions that has constants. - // csc.exe would automatically fold that for us, but by doing it here, we eliminate generate - // errors during compiling the test case. - if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) - { - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); - } + // Fold arithmetic binop expressions that has constants. + // csc.exe would automatically fold that for us, but by doing it here, we eliminate generate + // errors during compiling the test case. + if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) + { + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); + } - //TODO-config: Add MaxDepth in config - ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth >= 5 ? 0 : depth + 1); - ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth >= 5 ? 0 : depth + 1); + //TODO-config: Add MaxDepth in config + ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth >= 5 ? 0 : depth + 1); + ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth >= 5 ? 0 : depth + 1); - // For division, make sure that divisor is not 0 - if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) - { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, exprType, rhs); - } + // For division, make sure that divisor is not 0 + if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) + { + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, exprType, rhs); + } - return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); + return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); } case ExprKind.AssignExpression: { @@ -507,7 +546,20 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + ExpressionSyntax rhs = null; + + //TODO-config no. of attempts + int noOfAttempts = 0; + while (noOfAttempts++ < 5) + { + rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); + // Make sure that we do not end up with same lhs=lhs. + if (lhs.ToFullString() != rhs.ToFullString()) + { + break; + } + } + Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) @@ -516,7 +568,8 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); } - return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); + return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, + AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); } default: @@ -526,6 +579,31 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return null; } + /// + /// Generates assignment for variable name + /// + /// + public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string variableName) + { + ExpressionSyntax lhs = Annotate(Helpers.GetVariableAccessExpression(variableName), "specific-Var"); + ExpressionSyntax rhs = null; + + //TODO-config no. of attempts + int noOfAttempts = 0; + while (noOfAttempts++ < 5) + { + rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(exprType.PrimitiveType), exprType, 0); + // Make sure that we do not end up with same lhs=lhs. + if (lhs.ToFullString() != rhs.ToFullString()) + { + break; + } + } + Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); + + return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign"); + } + private Tree.ValueType GetRandomExprType() { //TODO:config - probability of struct variables @@ -582,7 +660,7 @@ public class MethodSignature new Weights(ParamValuePassing.None, 50), new Weights(ParamValuePassing.Ref, 25), new Weights(ParamValuePassing.Out, 15), - new Weights(ParamValuePassing.In, 10), + //new Weights(ParamValuePassing.In, 10), }; public MethodSignature(string methodName) @@ -626,9 +704,15 @@ public override string ToString() public class MethodParam { + public string ParamName; public Tree.ValueType ParamType; public ParamValuePassing PassingWay; + public override string ToString() + { + return $"{Enum.GetName(typeof(ParamValuePassing), PassingWay)} {ParamType} {ParamName}"; + } + //public MethodParam(Tree.ValueType paramType, ParamValuePassing passingWay) //{ // ParamType = paramType; @@ -638,6 +722,10 @@ public class MethodParam public enum ParamValuePassing { - None, In, Out, Ref + None, + //TODO-future: need to add ability of marking variables readonly + //In, + Out, + Ref }; } diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 960862a..f3da4e8 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -38,6 +38,11 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize statements foreach (StmtKind stmt in (StmtKind[])Enum.GetValues(typeof(StmtKind))) { + if (stmt == StmtKind.ReturnStatement) + { + // skip adding return as it will be added as the last statement of function + continue; + } AllStatements.Add(new Weights(stmt, Options.Lookup(stmt))); } diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 42cfcda..276cbb9 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -8,6 +8,7 @@ public enum StmtKind ForStatement, DoWhileStatement, WhileStatement, + ReturnStatement, //FunctionCallStatement, } From 47a7964ddc7f1422af817d1ce22d195d9559a692 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 8 Jan 2021 01:22:59 -0800 Subject: [PATCH 025/149] adjust weights --- Config/ConfigOptions.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 7ca2046..50ba3b4 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -18,18 +18,18 @@ public class ConfigOptions : OptionsBase // Expression weights public double LiteralWeight = 0.025; - public double VariableWeight = 0.5; + public double VariableWeight = 0.3; public double BinaryOpWeight = 1; - public double FunctionCallWeight = 0.5; - public double AssignWeight = 0.1; + public double MethodCallWeight = 0.23; + public double AssignWeight = 0.4; // Statement weights - public double VariableDeclarationWeight = 0.5; + public double VariableDeclarationWeight = 0.3; public double IfElseStatementWeight = 0.4; public double AssignStatementWeight = 0.5; - public double ForStatementWeight = 0.5; + public double ForStatementWeight = 0.4; public double DoWhileStatementWeight = 0.2; - public double WhileStatementWeight = 0.5; + public double WhileStatementWeight = 0.3; // Type weights public double BooleanWeight = 1; @@ -117,6 +117,8 @@ public class ConfigOptions : OptionsBase // number of testcases to create public long NumTestCases = 1; + // max number of statements in a block + public int MaxStatements = 5; public double Lookup(Tree.ValueType type) { From 09b48cf588ecbbd3e37e869d9dd668fd22daed07 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 8 Jan 2021 01:26:25 -0800 Subject: [PATCH 026/149] Foo() --- README.md | 3 +- TestClass.cs | 33 +++++++- TestMethod.cs | 189 ++++++++++++++++++++++++++++++++------------ Tree/AstUtils.cs | 27 ++++++- Tree/Expressions.cs | 2 +- 5 files changed, 196 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 9747821..5e72ffc 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 8. While loop 9. struct 10. Assignment expression -11. Initialize out, return statement \ No newline at end of file +11. Initialize out, return statement +12. Method call \ No newline at end of file diff --git a/TestClass.cs b/TestClass.cs index 13e6e4f..f7c6deb 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -46,9 +47,18 @@ public void RegisterMethod(MethodSignature methodSignature) Methods.Add(methodSignature); } - public MethodSignature GetRandomMethod() + /// + /// Get random method that returns specfic returnType. Null if no such + /// method is generated yet. + /// + public MethodSignature GetRandomMethod(Tree.ValueType returnType) { - return Methods[PRNG.Next(Methods.Count)]; + var matchingMethods = Methods.Where(m => m.ReturnType.Equals(returnType)).ToList(); + if (matchingMethods.Count == 0) + { + return null; + } + return matchingMethods[PRNG.Next(matchingMethods.Count())]; } public Scope CurrentScope @@ -75,6 +85,7 @@ public ClassDeclarationSyntax Generate() List classMembers = new List(); classMembers.AddRange(GenerateStructs()); + classMembers.AddRange(GenerateLeafMethods()); classMembers.AddRange(GenerateMethods()); // pop class scope @@ -175,5 +186,23 @@ private IList GenerateMethods() return methods; } + + private IList GenerateLeafMethods() + { + List leafMethods = new List(); + int leafMethodId = 0; + foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) + { + var testMethod = new TestLeafMethod(this, "LeafMethod" + leafMethodId++, variableType); + leafMethods.Add(testMethod.Generate()); + } + + foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) + { + var testMethod = new TestLeafMethod(this, "LeafMethod" + leafMethodId++, structType); + leafMethods.Add(testMethod.Generate()); + } + return leafMethods; + } } } diff --git a/TestMethod.cs b/TestMethod.cs index de9e6cc..c4f1b72 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -17,15 +17,21 @@ namespace Antigen /// public class TestMethod { - private TestClass testClass; - private TestCase TC => testClass.TC; - private string Name; + private readonly TestClass _testClass; + private TestCase TC => _testClass.TC; + protected readonly string Name; + protected readonly int _stmtCount; + + //TODO-config: Move this to ConfigOptions + private static readonly int s_maxStatements = 4; + #if DEBUG private Dictionary expressionsCount = new Dictionary(); private Dictionary statementsCount = new Dictionary(); #endif - private int variablesCount = 0; + private int _variablesCount = 0; + internal HashSet callsFromThisMethod = new HashSet(); public AstUtils GetASTUtils() @@ -33,32 +39,52 @@ public AstUtils GetASTUtils() return TC.AstUtils; } - private Scope MethodScope; - private bool takesParameters; - public MethodSignature MethodSignature { get; private set; } - public Scope CurrentScope => testClass.CurrentScope; + protected Scope MethodScope; + private readonly bool _takesParameters; + protected MethodSignature MethodSignature { get; set; } + public Scope CurrentScope => _testClass.CurrentScope; - public void PushScope(Scope scope) + protected void PushScope(Scope scope) { - testClass.PushScope(scope); + _testClass.PushScope(scope); } - public Scope PopScope() + protected Scope PopScope() { - Scope ret = testClass.PopScope(); + Scope ret = _testClass.PopScope(); //Debug.Assert(ret.Parent == ScopeStack.Peek()); return ret; } + /// + /// Creates leaf method that does not take parameters and has a single return statement. + /// + protected TestMethod(TestClass enclosingClass, string methodName, int stmtCount) + { + _testClass = enclosingClass; + Name = methodName; + MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); + _stmtCount = stmtCount; + } + + /// + /// Creates test method. + /// + /// + /// + /// public TestMethod(TestClass enclosingClass, string methodName, bool takesParams = true) { - testClass = enclosingClass; + _testClass = enclosingClass; Name = methodName; MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); - takesParameters = takesParams; + _takesParameters = takesParams; + + //TODO-config: Statements in a function + _stmtCount = PRNG.Next(1, s_maxStatements); } - public MethodDeclarationSyntax Generate() + public virtual MethodDeclarationSyntax Generate() { PushScope(MethodScope); @@ -68,7 +94,7 @@ public MethodDeclarationSyntax Generate() // TODO-TEMP initialize one variable of each type foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { - string variableName = Helpers.GetVariableName(variableType, variablesCount++); + string variableName = Helpers.GetVariableName(variableType, _variablesCount++); ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); @@ -79,7 +105,7 @@ public MethodDeclarationSyntax Generate() // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { - string variableName = Helpers.GetVariableName(structType, variablesCount++); + string variableName = Helpers.GetVariableName(structType, _variablesCount++); ExpressionSyntax rhs = Annotate(Helpers.GetObjectCreationExpression(structType.TypeName), "struct-init"); CurrentScope.AddLocal(structType, variableName); @@ -110,17 +136,21 @@ public MethodDeclarationSyntax Generate() CurrentScope.AddLocal(param.ParamType, param.ParamName); } - //TODO-config: Statements in a function - for (int i = 0; i < 5; i++) + for (int i = 0; i < _stmtCount; i++) { StmtKind cur = GetASTUtils().GetRandomStatemet(); methodBody.Add(StatementHelper(cur, 0)); } - // print all variables - foreach (string variableName in CurrentScope.AllVariables) + // If only statement in method is a return statement, + // do not print the variables we generated above. + if (_stmtCount > 0) { - methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + // print all variables + foreach (string variableName in CurrentScope.AllVariables) + { + methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + } } // return statement @@ -128,7 +158,7 @@ public MethodDeclarationSyntax Generate() PopScope(); - testClass.RegisterMethod(MethodSignature); + _testClass.RegisterMethod(MethodSignature); // Wrap everything in unchecked so we do not see overflow compilation errors return methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); @@ -137,11 +167,11 @@ public MethodDeclarationSyntax Generate() /// /// Generates method signature of this method. /// - private MethodDeclarationSyntax GenerateMethodSignature() + protected virtual MethodDeclarationSyntax GenerateMethodSignature() { MethodSignature = new MethodSignature(Name); int numOfParameters = 0; - if (takesParameters) + if (_takesParameters) { //TODO:config - No. of parameters numOfParameters = PRNG.Next(1, 10); @@ -150,7 +180,7 @@ private MethodDeclarationSyntax GenerateMethodSignature() List parameters = new List(); MethodSignature.Parameters = parameters; - List parameterNodes = new List(); + List parameterNodes = new List(); for (int paramIndex = 0; paramIndex < numOfParameters; paramIndex++) { @@ -194,25 +224,16 @@ private MethodDeclarationSyntax GenerateMethodSignature() PassingWay = passingWay }); parameterNodes.Add(parameterNode); - } - - - List finalPametersList = new List(); - - if (takesParameters) - { - finalPametersList.Add(parameterNodes[0]); - } - for (int paramIndex = 1; paramIndex < numOfParameters; paramIndex++) - { - finalPametersList.Add(Token(SyntaxKind.CommaToken)); - finalPametersList.Add(parameterNodes[paramIndex]); + if (paramIndex + 1 < numOfParameters) + { + parameterNodes.Add(Token(SyntaxKind.CommaToken)); + } } return MethodDeclaration(Helpers.GetTypeSyntax(MethodSignature.ReturnType), Name) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithParameterList(ParameterList(SeparatedList(finalPametersList))); + .WithParameterList(ParameterList(SeparatedList(parameterNodes))); } public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) @@ -223,7 +244,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { Tree.ValueType variableType = GetRandomExprType(); - string variableName = Helpers.GetVariableName(variableType, variablesCount++); + string variableName = Helpers.GetVariableName(variableType, _variablesCount++); ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); @@ -249,7 +270,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope elseBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); //TODO-config: Add MaxDepth in config - int ifcount = 3; + int ifcount = PRNG.Next(1, s_maxStatements); IList ifBody = new List(); PushScope(ifBranchScope); @@ -269,7 +290,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop 'if' body scope - int elsecount = 3; + int elsecount = PRNG.Next(1, s_maxStatements); IList elseBody = new List(); PushScope(elseBranchScope); @@ -346,7 +367,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); ForStatement forStmt = new ForStatement(TC); //TODO:config - int n = 3; // max statements + int n = PRNG.Next(1, s_maxStatements); forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); forStmt.NestNum = depth; forStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -390,7 +411,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); DoWhileStatement doStmt = new DoWhileStatement(TC); //TODO:config - int n = 3; // max statements + int n = PRNG.Next(1, s_maxStatements); doStmt.NestNum = depth; doStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -423,7 +444,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); WhileStatement whileStmt = new WhileStatement(TC); //TODO:config - int n = 3; // max statements + int n = PRNG.Next(1, s_maxStatements); whileStmt.NestNum = depth; whileStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -452,13 +473,16 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(Block(whileStmt.Generate(false)), "while-loop"); } case StmtKind.ReturnStatement: - Tree.ValueType returnType = MethodSignature.ReturnType; - if (returnType.PrimitiveType == Primitive.Void) { - return Annotate(ReturnStatement(), "Return"); + Tree.ValueType returnType = MethodSignature.ReturnType; + if (returnType.PrimitiveType == Primitive.Void) + { + return Annotate(ReturnStatement(), "Return"); + } + + ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); + return Annotate(ReturnStatement(returnExpr), "Return"); } - ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); - return Annotate(ReturnStatement(returnExpr), "Return"); default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; @@ -571,6 +595,41 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); } + case ExprKind.MethodCallExpression: + { + MethodSignature methodSig = _testClass.GetRandomMethod(exprType); + List argumentNodes = new List(); + int paramsCount = methodSig.Parameters.Count; + + for (int paramId = 0; paramId < paramsCount; paramId++) + { + MethodParam parameter = methodSig.Parameters[paramId]; + + Tree.ValueType argType = parameter.ParamType; + ExprKind argExprKind = parameter.PassingWay == ParamValuePassing.None ? GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType) : ExprKind.VariableExpression; + + ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth); + ArgumentSyntax argSyntax = Argument(argExpr); + + if (parameter.PassingWay == ParamValuePassing.Ref) + { + argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.RefKeyword)); + } + else if (parameter.PassingWay == ParamValuePassing.Out) + { + argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.OutKeyword)); + } + + argumentNodes.Add(argSyntax); + if (paramId + 1 < paramsCount) + { + argumentNodes.Add(Token(SyntaxKind.CommaToken)); + } + } + + return InvocationExpression(IdentifierName(methodSig.MethodName)) + .WithArgumentList(ArgumentList(SeparatedList(argumentNodes))); + } default: Debug.Assert(false, string.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); @@ -728,4 +787,32 @@ public enum ParamValuePassing Out, Ref }; + + public class TestLeafMethod : TestMethod + { + private Tree.ValueType ReturnType; + public TestLeafMethod(TestClass enclosingClass, string methodName, Tree.ValueType returnType) + : base(enclosingClass, methodName, 0) + { + ReturnType = returnType; + } + + protected override MethodDeclarationSyntax GenerateMethodSignature() + { + MethodSignature = new MethodSignature(Name); + MethodSignature.Parameters = new List(); + MethodSignature.ReturnType = ReturnType; + + return MethodDeclaration(Helpers.GetTypeSyntax(ReturnType), Name) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + } + + public override MethodDeclarationSyntax Generate() + { + GetASTUtils().EnterLeafMethod(); + var result = base.Generate(); + GetASTUtils().LeaveLeafMethod(); + return result; + } + } } diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index f3da4e8..b105d2e 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Antigen.Config; using Antigen.Statements; @@ -22,6 +23,7 @@ public class AstUtils private ConfigOptions Options; private RunOptions RunOptions; private TestCase TestCase; + private Weights MethodCallWeight; public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) { @@ -49,17 +51,23 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize expressions foreach (ExprKind expr in (ExprKind[])Enum.GetValues(typeof(ExprKind))) { - AllExpressions.Add(new Weights(expr, Options.Lookup(expr))); + var weight = new Weights(expr, Options.Lookup(expr)); ; + if (expr == ExprKind.MethodCallExpression) + { + MethodCallWeight = weight; + } + + AllExpressions.Add(weight); // For binary operation, there is no operator that don't have assign flag and that returns char or string // Hence do not choose binary expression if return is expected to be string if (expr != ExprKind.BinaryOpExpression) { - AllNonNumericExpressions.Add(new Weights(expr, Options.Lookup(expr))); + AllNonNumericExpressions.Add(weight); } if (expr == ExprKind.VariableExpression) { - AllStructExpressions.Add(new Weights(expr, Options.Lookup(expr))); + AllStructExpressions.Add(weight); } } @@ -70,6 +78,19 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) } } + public void EnterLeafMethod() + { + bool removed = AllExpressions.Remove(MethodCallWeight); + removed &= AllNonNumericExpressions.Remove(MethodCallWeight); + Debug.Assert(removed); + } + + public void LeaveLeafMethod() + { + AllExpressions.Add(MethodCallWeight); + AllNonNumericExpressions.Add(MethodCallWeight); + } + #region Random type methods public ValueType GetRandomExprType() { diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs index ddb26ef..a7959c0 100644 --- a/Tree/Expressions.cs +++ b/Tree/Expressions.cs @@ -6,7 +6,7 @@ public enum ExprKind VariableExpression, BinaryOpExpression, AssignExpression, - //FunctionCallExpression, + MethodCallExpression, } //public struct Expression From 454c5a6f40ee636fc4076539cc703020c2742fc2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 8 Jan 2021 09:59:37 -0800 Subject: [PATCH 027/149] Ensure all generated methods are called --- TestClass.cs | 37 +++++++++++------ TestMethod.cs | 110 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/TestClass.cs b/TestClass.cs index f7c6deb..9dbf6a8 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -26,7 +26,7 @@ public class TestClass public string ClassName; public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } - public List Methods { get; private set; } + private List> _methods { get; set; } public AstUtils GetASTUtils() { @@ -39,26 +39,38 @@ public TestClass(TestCase tc, string className) ClassScope = new Scope(tc); ClassName = className; TC = tc; - Methods = new List(); + _methods = new List>(); } public void RegisterMethod(MethodSignature methodSignature) { - Methods.Add(methodSignature); + double weight = 0.5; + if (methodSignature.MethodName.StartsWith("Leaf")) + { + // left methods have lower weight. try calling actual + // methods first. + weight = 0.20; + } + _methods.Add(new Weights(methodSignature, weight)); } + /// + /// Returns all non-leaf methods + /// + public List AllNonLeafMethods => _methods.Where(m => !m.Data.IsLeaf).Select(m => m.Data).ToList(); + /// /// Get random method that returns specfic returnType. Null if no such /// method is generated yet. /// public MethodSignature GetRandomMethod(Tree.ValueType returnType) { - var matchingMethods = Methods.Where(m => m.ReturnType.Equals(returnType)).ToList(); + var matchingMethods = _methods.Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); if (matchingMethods.Count == 0) { return null; } - return matchingMethods[PRNG.Next(matchingMethods.Count())]; + return PRNG.WeightedChoice(matchingMethods); } public Scope CurrentScope @@ -169,20 +181,19 @@ private IList GenerateMethods() { List methods = new List(); - methods.Add(ParseMemberDeclaration( -@$"public static void Main(string[] args) {{ - {ClassName} obj{ClassName} = new {ClassName}(); - obj{ClassName}.Method0(); -}} -")); - methods.Add(new TestMethod(this, "Method0", false).Generate()); - //TODO-config: No. of methods per class for (int i = 1; i < 5; i++) { var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); } + methods.Add(new TestMethod(this, "Method0", true).Generate()); + methods.Add(ParseMemberDeclaration( +@$"public static void Main(string[] args) {{ + {ClassName} obj{ClassName} = new {ClassName}(); + obj{ClassName}.Method0(); +}} +")); return methods; } diff --git a/TestMethod.cs b/TestMethod.cs index c4f1b72..ee904ce 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -40,7 +40,7 @@ public AstUtils GetASTUtils() } protected Scope MethodScope; - private readonly bool _takesParameters; + private readonly bool _isMainInvocation; protected MethodSignature MethodSignature { get; set; } public Scope CurrentScope => _testClass.CurrentScope; @@ -72,13 +72,13 @@ protected TestMethod(TestClass enclosingClass, string methodName, int stmtCount) /// /// /// - /// - public TestMethod(TestClass enclosingClass, string methodName, bool takesParams = true) + /// + public TestMethod(TestClass enclosingClass, string methodName, bool isMainInvocation = false) { _testClass = enclosingClass; Name = methodName; MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); - _takesParameters = takesParams; + _isMainInvocation = isMainInvocation; //TODO-config: Statements in a function _stmtCount = PRNG.Next(1, s_maxStatements); @@ -142,6 +142,21 @@ public virtual MethodDeclarationSyntax Generate() methodBody.Add(StatementHelper(cur, 0)); } + // For main invocation method, invoke all the other methods once + if (_isMainInvocation) + { + foreach (var nonLeafMethod in _testClass.AllNonLeafMethods) + { + //TODO-future: Select any assignOper + //Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); + + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.ReturnType, 0); + ExpressionSyntax rhs = MethodCallHelper(nonLeafMethod, 0); + + methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign")); + } + } + // If only statement in method is a return statement, // do not print the variables we generated above. if (_stmtCount > 0) @@ -171,11 +186,11 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() { MethodSignature = new MethodSignature(Name); int numOfParameters = 0; - if (_takesParameters) + if (!_isMainInvocation) { //TODO:config - No. of parameters numOfParameters = PRNG.Next(1, 10); - MethodSignature.ReturnType = GetRandomExprType(); + MethodSignature.ReturnType = GetRandomExprType(structProbability: 0.7); } List parameters = new List(); @@ -184,7 +199,7 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() for (int paramIndex = 0; paramIndex < numOfParameters; paramIndex++) { - var paramType = GetRandomExprType(); + var paramType = GetRandomExprType(structProbability: 0.7); var passingWay = PRNG.WeightedChoice(MethodSignature.ValuePassing); string paramName = "p_" + Helpers.GetVariableName(paramType, paramIndex); @@ -242,7 +257,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { case StmtKind.VariableDeclaration: { - Tree.ValueType variableType = GetRandomExprType(); + Tree.ValueType variableType = GetRandomExprType(structProbability: 0.3); string variableName = Helpers.GetVariableName(variableType, _variablesCount++); @@ -597,38 +612,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } case ExprKind.MethodCallExpression: { - MethodSignature methodSig = _testClass.GetRandomMethod(exprType); - List argumentNodes = new List(); - int paramsCount = methodSig.Parameters.Count; - - for (int paramId = 0; paramId < paramsCount; paramId++) - { - MethodParam parameter = methodSig.Parameters[paramId]; - - Tree.ValueType argType = parameter.ParamType; - ExprKind argExprKind = parameter.PassingWay == ParamValuePassing.None ? GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType) : ExprKind.VariableExpression; - - ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth); - ArgumentSyntax argSyntax = Argument(argExpr); - - if (parameter.PassingWay == ParamValuePassing.Ref) - { - argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.RefKeyword)); - } - else if (parameter.PassingWay == ParamValuePassing.Out) - { - argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.OutKeyword)); - } - - argumentNodes.Add(argSyntax); - if (paramId + 1 < paramsCount) - { - argumentNodes.Add(Token(SyntaxKind.CommaToken)); - } - } - - return InvocationExpression(IdentifierName(methodSig.MethodName)) - .WithArgumentList(ArgumentList(SeparatedList(argumentNodes))); + return MethodCallHelper(_testClass.GetRandomMethod(exprType), depth); } default: @@ -663,10 +647,46 @@ public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign"); } - private Tree.ValueType GetRandomExprType() + private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) + { + //MethodSignature methodSig = _testClass.GetRandomMethod(exprType); + List argumentNodes = new List(); + int paramsCount = methodSig.Parameters.Count; + + for (int paramId = 0; paramId < paramsCount; paramId++) + { + MethodParam parameter = methodSig.Parameters[paramId]; + + Tree.ValueType argType = parameter.ParamType; + ExprKind argExprKind = parameter.PassingWay == ParamValuePassing.None ? GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType) : ExprKind.VariableExpression; + + ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth); + ArgumentSyntax argSyntax = Argument(argExpr); + + if (parameter.PassingWay == ParamValuePassing.Ref) + { + argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.RefKeyword)); + } + else if (parameter.PassingWay == ParamValuePassing.Out) + { + argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.OutKeyword)); + } + + argumentNodes.Add(argSyntax); + if (paramId + 1 < paramsCount) + { + argumentNodes.Add(Token(SyntaxKind.CommaToken)); + } + } + + return InvocationExpression(IdentifierName(methodSig.MethodName)) + .WithArgumentList(ArgumentList(SeparatedList(argumentNodes))); + } + + private Tree.ValueType GetRandomExprType(double structProbability) { //TODO:config - probability of struct variables - if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) + if (PRNG.Decide(structProbability) && CurrentScope.NumOfStructTypes > 0) { return CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; } @@ -712,6 +732,7 @@ public class MethodSignature public string MethodName; public Tree.ValueType ReturnType; public List Parameters; + public bool IsLeaf; //TODO:config public static List> ValuePassing = new() @@ -722,11 +743,12 @@ public class MethodSignature //new Weights(ParamValuePassing.In, 10), }; - public MethodSignature(string methodName) + public MethodSignature(string methodName, bool isLeaf = false) { MethodName = methodName; ReturnType = Tree.ValueType.ForVoid(); Parameters = new List(); + IsLeaf = isLeaf; } public override bool Equals(object obj) @@ -799,7 +821,7 @@ public TestLeafMethod(TestClass enclosingClass, string methodName, Tree.ValueTyp protected override MethodDeclarationSyntax GenerateMethodSignature() { - MethodSignature = new MethodSignature(Name); + MethodSignature = new MethodSignature(Name, isLeaf: true); MethodSignature.Parameters = new List(); MethodSignature.ReturnType = ReturnType; From 7994f1a49c036256364d893fdf7c149a627a04e9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 10 Jan 2021 00:48:17 -0800 Subject: [PATCH 028/149] static variables, noinlining leaf method --- Helpers/Constants.cs | 2 +- Helpers/Expressions.cs | 17 +++++++++ TestCase.cs | 19 +++++++--- TestClass.cs | 55 +++++++++++++++++++++++++++ TestMethod.cs | 85 +++++++++++++++++++++++++++++------------- 5 files changed, 146 insertions(+), 32 deletions(-) diff --git a/Helpers/Constants.cs b/Helpers/Constants.cs index 4fdc2bf..83b996d 100644 --- a/Helpers/Constants.cs +++ b/Helpers/Constants.cs @@ -12,6 +12,6 @@ namespace Antigen { public static class Constants { - public static string LoopInvariantName = "loopInvariant"; + public static string LoopInvariantName = "s_loopInvariant"; } } diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index 5c0fc28..ca0b9b4 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -1,4 +1,6 @@ using Antigen.Tree; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; @@ -35,5 +37,20 @@ public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueT return parenExpr; } + + public static SyntaxList NoInlineAttr => + SingletonList( + AttributeList( + SingletonSeparatedList( + Attribute( + IdentifierName("MethodImpl")) + .WithArgumentList( + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("MethodImplOptions"), + IdentifierName("NoInlining"))))))))); } } diff --git a/TestCase.cs b/TestCase.cs index 6fb8bec..d0b2071 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -67,9 +67,11 @@ public TestCase(int testId, RunOptions runOptions) public void Generate() { - UsingDirectiveSyntax usingDirective = - UsingDirective(IdentifierName("System")) - .WithUsingKeyword(Token(TriviaList(new[]{ + List usingDirective = + new List() + { + UsingDirective(IdentifierName("System")) + .WithUsingKeyword(Token(TriviaList(new[]{ Comment("// Licensed to the .NET Foundation under one or more agreements."), Comment("// The .NET Foundation licenses this file to you under the MIT license."), Comment("// See the LICENSE file in the project root for more information."), @@ -77,12 +79,19 @@ public void Generate() Comment("// This file is auto-generated."), Comment("// Seed: " + PRNG.GetSeed()), Comment("//"), - }), SyntaxKind.UsingKeyword, TriviaList())); + }), SyntaxKind.UsingKeyword, TriviaList())), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("System"), + IdentifierName("Runtime")), + IdentifierName("CompilerServices"))) + }; ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); testCaseRoot = CompilationUnit() - .WithUsings(SingletonList(usingDirective)) + .WithUsings(new SyntaxList(usingDirective)) .WithMembers(new SyntaxList(klass)).NormalizeWhitespace(); } diff --git a/TestClass.cs b/TestClass.cs index 9dbf6a8..d64e971 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -97,6 +97,7 @@ public ClassDeclarationSyntax Generate() List classMembers = new List(); classMembers.AddRange(GenerateStructs()); + classMembers.AddRange(GenerateStaticFields()); classMembers.AddRange(GenerateLeafMethods()); classMembers.AddRange(GenerateMethods()); @@ -198,6 +199,9 @@ private IList GenerateMethods() return methods; } + /// + /// Generate leaf methods in this class. + /// private IList GenerateLeafMethods() { List leafMethods = new List(); @@ -215,5 +219,56 @@ private IList GenerateLeafMethods() } return leafMethods; } + + /// + /// Generate static fields in this class. + /// + private IList GenerateStaticFields() + { + List fields = new List(); + + // TODO-TEMP initialize one variable of each type + int _variablesCount = 0; + foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) + { + string variableName = "s_" + Helpers.GetVariableName(variableType, _variablesCount++); + + ExpressionSyntax rhs = Helpers.GetLiteralExpression(variableType); + CurrentScope.AddLocal(variableType, variableName); + + fields.Add(FieldDeclaration(Helpers.GetVariableDeclaration(variableType, variableName, rhs)) + .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + } + + // TODO-TEMP initialize one variable of each struct type + foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) + { + string variableName = "s_" + Helpers.GetVariableName(structType, _variablesCount++); + + ExpressionSyntax rhs = Helpers.GetObjectCreationExpression(structType.TypeName); + CurrentScope.AddLocal(structType, variableName); + + // Add all the fields to the scope + var listOfStructFields = CurrentScope.GetStructFields(structType); + foreach (var structField in listOfStructFields) + { + CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); + } + + fields.Add(FieldDeclaration(Helpers.GetVariableDeclaration(structType, variableName, rhs)) + .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + } + + //TODO: Define some more constants + fields.Add( + FieldDeclaration( + Helpers.GetVariableDeclaration( + Tree.ValueType.ForPrimitive(Primitive.Int), + Constants.LoopInvariantName, + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10))))) + .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + + return fields; + } } } diff --git a/TestMethod.cs b/TestMethod.cs index ee904ce..2c016b1 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -56,6 +56,14 @@ protected Scope PopScope() return ret; } + /// + /// Register the method in enclosing class. + /// + protected void RegisterMethod(MethodSignature methodSignature) + { + _testClass.RegisterMethod(methodSignature); + } + /// /// Creates leaf method that does not take parameters and has a single return statement. /// @@ -94,20 +102,31 @@ public virtual MethodDeclarationSyntax Generate() // TODO-TEMP initialize one variable of each type foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { + //TODO-config: Only declare again 20% of variables + if (PRNG.Decide(0.8)) + { + continue; + } + string variableName = Helpers.GetVariableName(variableType, _variablesCount++); ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); - methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs))); + methodBody.Add(Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "var-init")); } // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { + //TODO-config: Only declare again 20% of variables + if (PRNG.Decide(0.8)) + { + continue; + } + string variableName = Helpers.GetVariableName(structType, _variablesCount++); - ExpressionSyntax rhs = Annotate(Helpers.GetObjectCreationExpression(structType.TypeName), "struct-init"); CurrentScope.AddLocal(structType, variableName); // Add all the fields to the scope @@ -117,17 +136,11 @@ public virtual MethodDeclarationSyntax Generate() CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); } - methodBody.Add(LocalDeclarationStatement(Helpers.GetVariableDeclaration(structType, variableName, rhs))); + methodBody.Add(Annotate(LocalDeclarationStatement( + Helpers.GetVariableDeclaration(structType, variableName, + Helpers.GetObjectCreationExpression(structType.TypeName))), "struct-init")); } - //TODO: Define some more constants - methodBody.Add( - LocalDeclarationStatement( - Helpers.GetVariableDeclaration( - Tree.ValueType.ForPrimitive(Primitive.Int), - Constants.LoopInvariantName, - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10)))))); - // TODO-TEMP initialize out and ref method parameters var paramsToInitialize = MethodSignature.Parameters.Where(p => p.PassingWay == ParamValuePassing.Out); foreach (MethodParam param in paramsToInitialize) @@ -155,6 +168,12 @@ public virtual MethodDeclarationSyntax Generate() methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign")); } + + // print all static variables + foreach (string variableName in _testClass.ClassScope.AllVariables) + { + methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + } } // If only statement in method is a return statement, @@ -173,7 +192,7 @@ public virtual MethodDeclarationSyntax Generate() PopScope(); - _testClass.RegisterMethod(MethodSignature); + RegisterMethod(MethodSignature); // Wrap everything in unchecked so we do not see overflow compilation errors return methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); @@ -793,12 +812,6 @@ public override string ToString() { return $"{Enum.GetName(typeof(ParamValuePassing), PassingWay)} {ParamType} {ParamName}"; } - - //public MethodParam(Tree.ValueType paramType, ParamValuePassing passingWay) - //{ - // ParamType = paramType; - // PassingWay = passi - //} } public enum ParamValuePassing @@ -812,29 +825,49 @@ public enum ParamValuePassing public class TestLeafMethod : TestMethod { - private Tree.ValueType ReturnType; + private Tree.ValueType _returnType; public TestLeafMethod(TestClass enclosingClass, string methodName, Tree.ValueType returnType) : base(enclosingClass, methodName, 0) { - ReturnType = returnType; + _returnType = returnType; } protected override MethodDeclarationSyntax GenerateMethodSignature() { - MethodSignature = new MethodSignature(Name, isLeaf: true); - MethodSignature.Parameters = new List(); - MethodSignature.ReturnType = ReturnType; + MethodSignature = new MethodSignature(Name, isLeaf: true) + { + Parameters = new List(), + ReturnType = _returnType + }; - return MethodDeclaration(Helpers.GetTypeSyntax(ReturnType), Name) + var methodDecl = MethodDeclaration(Helpers.GetTypeSyntax(_returnType), Name) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + + //TODO-config: 50% of time, add attribute of NoInline + if (PRNG.Decide(0.5)) + { + methodDecl = methodDecl.WithAttributeLists(Helpers.NoInlineAttr); + } + + return methodDecl; } public override MethodDeclarationSyntax Generate() { GetASTUtils().EnterLeafMethod(); - var result = base.Generate(); + + // return statement + MethodDeclarationSyntax methodDeclaration = GenerateMethodSignature(); + IList methodBody = new List(); + + methodBody.Add(StatementHelper(StmtKind.ReturnStatement, 0)); + + RegisterMethod(MethodSignature); + + // Wrap everything in unchecked so we do not see overflow compilation errors + var leafMethod = methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); GetASTUtils().LeaveLeafMethod(); - return result; + return leafMethod; } } } From 625d5943d5eaab0cd6775d85fe9e42f380be9150 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 10 Jan 2021 23:02:46 -0800 Subject: [PATCH 029/149] wip:trimmer --- Config/RunOptions.cs | 2 + Helpers/TestRunner.cs | 181 +++++++++++++++++++ Program.cs | 11 +- TestCase.cs | 170 ++---------------- Trimmer/Rewriters/AssignStmtRemoval.cs | 27 +++ Trimmer/Rewriters/DoWhileStmtRemoval.cs | 27 +++ Trimmer/Rewriters/ForStmtRemoval.cs | 27 +++ Trimmer/Rewriters/IfElseStmtRemoval.cs | 27 +++ Trimmer/Rewriters/LocalDeclStmtRemoval.cs | 27 +++ Trimmer/Rewriters/SyntaxRewriter.cs | 45 +++++ Trimmer/Rewriters/WhileStmtRemoval.cs | 27 +++ Trimmer/TestTrimmer.cs | 208 ++++++++++++++++++++++ 12 files changed, 624 insertions(+), 155 deletions(-) create mode 100644 Helpers/TestRunner.cs create mode 100644 Trimmer/Rewriters/AssignStmtRemoval.cs create mode 100644 Trimmer/Rewriters/DoWhileStmtRemoval.cs create mode 100644 Trimmer/Rewriters/ForStmtRemoval.cs create mode 100644 Trimmer/Rewriters/IfElseStmtRemoval.cs create mode 100644 Trimmer/Rewriters/LocalDeclStmtRemoval.cs create mode 100644 Trimmer/Rewriters/SyntaxRewriter.cs create mode 100644 Trimmer/Rewriters/WhileStmtRemoval.cs create mode 100644 Trimmer/TestTrimmer.cs diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index 10c0f5f..4841d1a 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -23,5 +23,7 @@ public class RunOptions : OptionsBase // Full path to CoreRun.exe public string CoreRun = null; + + public readonly string MainMethodName = "Main"; } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs new file mode 100644 index 0000000..9be8347 --- /dev/null +++ b/Helpers/TestRunner.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; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Antigen.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; + +namespace Antigen +{ + public class TestRunner + { + private static TestRunner _testRunner; + private RunOptions RunOptions; + + private TestRunner(RunOptions runOptions) + { + RunOptions = runOptions; + } + + public static TestRunner GetInstance(RunOptions runOptions) + { + if (_testRunner == null) + { + _testRunner = new TestRunner(runOptions); + } + return _testRunner; + } + + /// + /// Compiles the generated . + /// + /// + internal CompileResult Compile(SyntaxTree programTree, string assemblyName) + { + string corelibPath = typeof(object).Assembly.Location; + string otherAssembliesPath = Path.GetDirectoryName(corelibPath); + MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); + MetadataReference systemConsole = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Console.dll")); + MetadataReference systemRuntime = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Runtime.dll")); + MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location); + MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location); + + MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; + + var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, references, Rsln.CompileOptions); + string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{assemblyName}.exe"); + + using (var ms = new MemoryStream()) + { + EmitResult result; + try + { + result = cc.Emit(ms); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return new CompileResult(ex, ImmutableArray.Empty, null, null); + } + + if (!result.Success) + return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null, null); + + ms.Seek(0, SeekOrigin.Begin); + File.WriteAllBytes(assemblyFullPath, ms.ToArray()); + + return new CompileResult(null, ImmutableArray.Empty, assemblyName, assemblyFullPath); + } + } + + /// + /// Execute the compiled assembly in an environment that has . + /// + /// + internal string Execute(CompileResult compileResult, Dictionary environmentVariables) + { + Debug.Assert(compileResult.AssemblyFullPath != null); + if (false) + { + //TODO: if execute in debug vs. release dotnet.exe + Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); + Type testClassType = asm.GetType(compileResult.AssemblyName); + MethodInfo mainMethodInfo = testClassType.GetMethod(RunOptions.MainMethodName); + Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); + + Exception ex = null; + TextWriter origOut = Console.Out; + + MemoryStream ms = new MemoryStream(); + StreamWriter sw = new StreamWriter(ms, Encoding.UTF8); + + try + { + Console.SetOut(sw); + entryPoint(null); + } + catch (Exception caughtEx) + { + ex = caughtEx; + Console.WriteLine(caughtEx); + } + finally + { + Console.SetOut(origOut); + sw.Close(); + } + + return Encoding.UTF8.GetString(ms.ToArray()); + } + else + { + ProcessStartInfo info = new ProcessStartInfo + { + FileName = RunOptions.CoreRun, + Arguments = compileResult.AssemblyFullPath, + WorkingDirectory = Environment.CurrentDirectory, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + }; + + foreach (var envVar in environmentVariables) + { + info.EnvironmentVariables[envVar.Key] = envVar.Value; + } + + using (Process proc = Process.Start(info)) + { + string results = proc.StandardOutput.ReadToEnd(); + results += proc.StandardError.ReadToEnd(); + proc.WaitForExit(1 * 60 * 1000); // 1 minute + + return results; + } + } + } + } + + internal class CompileResult + { + public CompileResult(Exception roslynException, ImmutableArray diagnostics, string assemblyName, string assemblyFullPath) + { + RoslynException = roslynException; + List errors = new List(); + List warnings = new List(); + foreach (var diag in diagnostics) + { + if (diag.Severity == DiagnosticSeverity.Error) + { + errors.Add(diag); + } + else if (diag.Severity == DiagnosticSeverity.Warning) + { + errors.Add(diag); + } + } + CompileErrors = errors.ToImmutableArray(); + CompileWarnings = warnings.ToImmutableArray(); + AssemblyName = assemblyName; + AssemblyFullPath = assemblyFullPath; + } + + public string AssemblyName { get; } + public Exception RoslynException { get; } + public ImmutableArray CompileErrors { get; } + public ImmutableArray CompileWarnings { get; } + public string AssemblyFullPath { get; } + } +} diff --git a/Program.cs b/Program.cs index 8b8497b..878edb8 100644 --- a/Program.cs +++ b/Program.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Diagnostics; using Antigen.Config; +using Antigen.Trimmer; namespace Antigen { class Program { - public static RunOptions RunOptions = new RunOptions(); static void Main(string[] args) @@ -16,6 +16,15 @@ static void Main(string[] args) RunOptions.CoreRun = args[0]; + // trimmer + if (args.Length > 1) + { + string testCaseToTrim = args[1]; + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, RunOptions); + testTrimmer.Trim(); + return; + } + int testId = 1; Dictionary stats = new Dictionary() { diff --git a/TestCase.cs b/TestCase.cs index d0b2071..2b21829 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -40,7 +40,6 @@ public enum CompilationType #region PreComputed roslyn syntax tress #endregion - private const string MainMethodName = "Main"; private List knownDiffs = new List() { "System.OverflowException: Value was either too large or too small for a Decimal.", @@ -54,6 +53,7 @@ public enum CompilationType //private List propertiesList; //private List fieldsList; + private static TestRunner TestRunner; private static RunOptions RunOptions; public string Name { get; private set; } public AstUtils AstUtils { get; private set; } @@ -63,6 +63,7 @@ public TestCase(int testId, RunOptions runOptions) RunOptions = runOptions; AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; + TestRunner = TestRunner.GetInstance(RunOptions); } public void Generate() @@ -97,8 +98,19 @@ public void Generate() public TestResult Verify() { +#if DEBUG + SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; + SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); + FindTreeDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); +#else + // In release, make sure that we didn't end up generating wrong syntax tree, + // hence parse the text to reconstruct the tree. + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); +#endif + StringBuilder fileContents = new StringBuilder(); - CompileResult compileResult = Compile(); + CompileResult compileResult = TestRunner.Compile(syntaxTree, Name); if (compileResult.AssemblyFullPath == null) { fileContents.AppendLine(testCaseRoot.ToFullString()); @@ -121,7 +133,7 @@ public TestResult Verify() // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); //} - string baseline = Execute(compileResult, Rsln.BaselineEnvVars); + string baseline = TestRunner.Execute(compileResult, Rsln.BaselineEnvVars); var selectedVars = Rsln.TestEnvVars[PRNG.Next(Rsln.TestEnvVars.Count)].Vars; var testEnvVariables = new Dictionary(); @@ -135,7 +147,7 @@ public TestResult Verify() testEnvVariables[selectedVar.Key] = selectedVar.Value; } - string test = Execute(compileResult, testEnvVariables); + string test = TestRunner.Execute(compileResult, testEnvVariables); if (baseline == test) { @@ -251,155 +263,5 @@ private void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) return; } } - - /// - /// Compiles the generated . - /// - /// - private CompileResult Compile() - { -#if DEBUG - SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; - SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); - FindTreeDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); -#else - // In release, make sure that we didn't end up generating wrong syntax tree, - // hence parse the text to reconstruct the tree. - - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); -#endif - - string corelibPath = typeof(object).Assembly.Location; - string otherAssembliesPath = Path.GetDirectoryName(corelibPath); - MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); - MetadataReference systemConsole = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Console.dll")); - MetadataReference systemRuntime = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Runtime.dll")); - MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location); - MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location); - - MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - - var cc = CSharpCompilation.Create($"{Name}.exe", new SyntaxTree[] { syntaxTree }, references, Rsln.CompileOptions); - string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{Name}.exe"); - - using (var ms = new MemoryStream()) - { - EmitResult result; - try - { - result = cc.Emit(ms); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - return new CompileResult(ex, ImmutableArray.Empty, null); - } - - if (!result.Success) - return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null); - - ms.Seek(0, SeekOrigin.Begin); - File.WriteAllBytes(assemblyFullPath, ms.ToArray()); - - return new CompileResult(null, ImmutableArray.Empty, assemblyFullPath); - } - } - - /// - /// Execute the compiled assembly in an environment that has . - /// - /// - private string Execute(CompileResult compileResult, Dictionary environmentVariables) - { - Debug.Assert(compileResult.AssemblyFullPath != null); - if (false) - { - //TODO: if execute in debug vs. release dotnet.exe - Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); - Type testClassType = asm.GetType(Name); - MethodInfo mainMethodInfo = testClassType.GetMethod(MainMethodName); - Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); - - Exception ex = null; - TextWriter origOut = Console.Out; - - MemoryStream ms = new MemoryStream(); - StreamWriter sw = new StreamWriter(ms, Encoding.UTF8); - - try - { - Console.SetOut(sw); - entryPoint(null); - } - catch (Exception caughtEx) - { - ex = caughtEx; - Console.WriteLine(caughtEx); - } - finally - { - Console.SetOut(origOut); - sw.Close(); - } - - return Encoding.UTF8.GetString(ms.ToArray()); - } - else - { - ProcessStartInfo info = new ProcessStartInfo - { - FileName = RunOptions.CoreRun, - Arguments = compileResult.AssemblyFullPath, - WorkingDirectory = Environment.CurrentDirectory, - RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, - UseShellExecute = false, - }; - - foreach (var envVar in environmentVariables) - { - info.EnvironmentVariables[envVar.Key] = envVar.Value; - } - - using (Process proc = Process.Start(info)) - { - string results = proc.StandardOutput.ReadToEnd(); - results += proc.StandardError.ReadToEnd(); - proc.WaitForExit(1 * 60 * 1000); // 1 minute - - return results; - } - } - } - } - - internal class CompileResult - { - public CompileResult(Exception roslynException, ImmutableArray diagnostics, string assemblyFullPath) - { - RoslynException = roslynException; - List errors = new List(); - List warnings = new List(); - foreach (var diag in diagnostics) - { - if (diag.Severity == DiagnosticSeverity.Error) - { - errors.Add(diag); - } - else if (diag.Severity == DiagnosticSeverity.Warning) - { - errors.Add(diag); - } - } - CompileErrors = errors.ToImmutableArray(); - CompileWarnings = warnings.ToImmutableArray(); - AssemblyFullPath = assemblyFullPath; - } - - public Exception RoslynException { get; } - public ImmutableArray CompileErrors { get; } - public ImmutableArray CompileWarnings { get; } - public string AssemblyFullPath { get; } } } diff --git a/Trimmer/Rewriters/AssignStmtRemoval.cs b/Trimmer/Rewriters/AssignStmtRemoval.cs new file mode 100644 index 0000000..cc0993c --- /dev/null +++ b/Trimmer/Rewriters/AssignStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class AssignStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitExpressionStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/DoWhileStmtRemoval.cs b/Trimmer/Rewriters/DoWhileStmtRemoval.cs new file mode 100644 index 0000000..1b9e515 --- /dev/null +++ b/Trimmer/Rewriters/DoWhileStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class DoWhileStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitDoStatement(DoStatementSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitDoStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/ForStmtRemoval.cs b/Trimmer/Rewriters/ForStmtRemoval.cs new file mode 100644 index 0000000..1b1752e --- /dev/null +++ b/Trimmer/Rewriters/ForStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class ForStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitForStatement(ForStatementSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitForStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/IfElseStmtRemoval.cs b/Trimmer/Rewriters/IfElseStmtRemoval.cs new file mode 100644 index 0000000..19b613a --- /dev/null +++ b/Trimmer/Rewriters/IfElseStmtRemoval.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.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class IfElseStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitIfStatement(IfStatementSyntax node) + { + if (node.ToFullString().Contains("loopInvariant")) + { + // do not count them + return base.VisitIfStatement(node); + } + + return base.VisitIfStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/LocalDeclStmtRemoval.cs new file mode 100644 index 0000000..44326be --- /dev/null +++ b/Trimmer/Rewriters/LocalDeclStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class LocalDeclStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitLocalDeclarationStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/SyntaxRewriter.cs b/Trimmer/Rewriters/SyntaxRewriter.cs new file mode 100644 index 0000000..b99f6c0 --- /dev/null +++ b/Trimmer/Rewriters/SyntaxRewriter.cs @@ -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. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class SyntaxRewriter : CSharpSyntaxRewriter + { + protected int id = -1; + protected int currId = 0; + protected bool removeAll = true; + + public void RemoveAll() + { + removeAll = true; + } + + public void RemoveOneByOne() + { + removeAll = false; + } + + /// + /// Returns total visited in recent call to Visit(). + /// + public int TotalVisited => currId; + + public void Reset() + { + currId = 0; + } + + public void UpdateId(int newId) + { + id = newId; + } + } +} diff --git a/Trimmer/Rewriters/WhileStmtRemoval.cs b/Trimmer/Rewriters/WhileStmtRemoval.cs new file mode 100644 index 0000000..35a2114 --- /dev/null +++ b/Trimmer/Rewriters/WhileStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class WhileStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitWhileStatement(node); + } + } +} diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs new file mode 100644 index 0000000..cfdca3d --- /dev/null +++ b/Trimmer/TestTrimmer.cs @@ -0,0 +1,208 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using System.Threading.Tasks; +using Antigen.Config; +using Antigen.Trimmer.Rewriters; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen.Trimmer +{ + public class TestTrimmer + { + RunOptions RunOptions; + private string _testFileToTrim; + private static TestRunner _testRunner; + + public TestTrimmer(string testFileToTrim, RunOptions runOptions) + { + RunOptions = runOptions; + _testFileToTrim = testFileToTrim; + _testRunner = TestRunner.GetInstance(RunOptions); + } + + public void Trim() + { + var treeRoot = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + + + //TODO: populate baseline and test envvars: + Dictionary baselineEnvVars = Rsln.BaselineEnvVars; + Dictionary testEnvVars = new Dictionary() + { + {"COMPlus_JitStress", "2" }, + {"COMPlus_JitStressRegs", "0x10000" }, + {"COMPlus_TieredCompilation", "0" } + }; + TestResult reproTestResult = TestResult.Fail; + + //IfElseStmtRemoval ifElse = new IfElseStmtRemoval(); + //ifElse.UpdateId(0); + //var newRoot = ifElse.Visit(treeRoot); + //File.WriteAllText(@"E:\temp\antigen-trimmer\1.trim.g.cs", newRoot.ToFullString()); + + List trimmerList = new List() + { + new DoWhileStmtRemoval(), + new ForStmtRemoval(), + new WhileStmtRemoval(), + new IfElseStmtRemoval(), + new AssignStmtRemoval(), + new LocalDeclStmtRemoval(), + }; + + // pick category + SyntaxNode recentTree = treeRoot; + int iterId = 0; + foreach (var trimmer in trimmerList) + { + SyntaxNode treeBeforeTrim = recentTree; + + // remove all + Console.Write($"{iterId}. {trimmer.GetType()}"); + + trimmer.RemoveAll(); + SyntaxNode treeAfterTrim = trimmer.Visit(recentTree); + + //repros = Verify(treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult; + + // compile, execute and repro + if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + { + // move to next trimmer + recentTree = treeAfterTrim; + Console.WriteLine(" - Success"); + continue; + } + else + { + recentTree = treeBeforeTrim; + Console.WriteLine(" - Revert"); + } + + int noOfNodes = trimmer.TotalVisited; + + trimmer.Reset(); + trimmer.RemoveOneByOne(); + + int nodeId = 0; + while (nodeId < noOfNodes) + { + Console.Write($"{iterId}. {trimmer.GetType()}, nodeId = {nodeId}"); + trimmer.Reset(); + trimmer.UpdateId(nodeId); + treeAfterTrim = trimmer.Visit(recentTree); + + // compile, execute and repro + if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + { + // move to next trimmer + recentTree = treeAfterTrim; + + // We have just removed a node, so decrease nodes count + noOfNodes--; + + Console.WriteLine(" - Success"); + + } + else + { + recentTree = treeBeforeTrim; + + // Go to next nodeId + nodeId++; + + Console.WriteLine(" - Revert"); + } + } + } + } + + private List knownDiffs = new List() + { + "System.OverflowException: Value was either too large or too small for a Decimal.", + "System.DivideByZeroException: Attempted to divide by zero.", + }; + + //TODO: refactor and merge with TestCase's Verify + private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary baselineEnvVars, Dictionary testEnvVars/*, bool skipBaseline*/) + { + StringBuilder fileContents = new StringBuilder(); + CompileResult compileResult = _testRunner.Compile(programRootNode.SyntaxTree, iterId); + if (compileResult.AssemblyFullPath == null) + { + return TestResult.CompileError; + } + //else + //{ + // string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); + // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); + //} + + string baseline = _testRunner.Execute(compileResult, Rsln.BaselineEnvVars); + string test = _testRunner.Execute(compileResult, testEnvVars); + + if (baseline == test) + { + try + { + File.Delete(compileResult.AssemblyFullPath); + } + catch (Exception) + { + // ignore errors + } + return TestResult.Pass; + } + + foreach (string knownError in knownDiffs) + { + if (baseline.Contains(knownError) && test.Contains(knownError)) + { + return TestResult.Pass; + } + } + + fileContents.AppendLine(programRootNode.ToFullString()); + fileContents.AppendLine("/*"); + fileContents.AppendLine($"Got output diff:"); + + fileContents.AppendLine("--------- Baseline --------- "); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in baselineEnvVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); + fileContents.AppendLine(baseline); + + fileContents.AppendLine("--------- Test --------- "); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in testEnvVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); + fileContents.AppendLine(test); + fileContents.AppendLine("*/"); + + string failedFileName = $"{iterId}-lkg"; + string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); + File.WriteAllText(failFile, fileContents.ToString()); + + File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); + return TestResult.Fail; + } + } +} From 0efadd606831aad88254774e11d50f29b8f93f8b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 16 Jan 2021 02:39:49 -0800 Subject: [PATCH 030/149] working trimmer for statement --- README.md | 3 +- .../Rewriters/Expressions/BinaryExpRemoval.cs | 29 +++ .../Rewriters/Expressions/CastExprRemoval.cs | 27 +++ .../IdentityNameExprRemoval.cs} | 6 +- .../LiteralExprRemoval.cs} | 6 +- .../Expressions/MemberAccessExprRemoval.cs | 27 +++ .../Rewriters/Expressions/ParenExprRemoval.cs | 27 +++ .../Rewriters/Statements/AssignStmtRemoval.cs | 35 ++++ Trimmer/Rewriters/Statements/BlockRemoval.cs | 28 +++ .../{ => Statements}/DoWhileStmtRemoval.cs | 0 .../{ => Statements}/ForStmtRemoval.cs | 0 .../{ => Statements}/IfElseStmtRemoval.cs | 5 + .../Statements/LocalDeclStmtRemoval.cs | 36 ++++ .../Statements/MethodDeclStmtRemoval.cs | 27 +++ .../{ => Statements}/SyntaxRewriter.cs | 12 ++ .../{ => Statements}/WhileStmtRemoval.cs | 0 Trimmer/TestTrimmer.cs | 176 +++++++++++------- 17 files changed, 365 insertions(+), 79 deletions(-) create mode 100644 Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs create mode 100644 Trimmer/Rewriters/Expressions/CastExprRemoval.cs rename Trimmer/Rewriters/{AssignStmtRemoval.cs => Expressions/IdentityNameExprRemoval.cs} (74%) rename Trimmer/Rewriters/{LocalDeclStmtRemoval.cs => Expressions/LiteralExprRemoval.cs} (72%) create mode 100644 Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs create mode 100644 Trimmer/Rewriters/Expressions/ParenExprRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/AssignStmtRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/BlockRemoval.cs rename Trimmer/Rewriters/{ => Statements}/DoWhileStmtRemoval.cs (100%) rename Trimmer/Rewriters/{ => Statements}/ForStmtRemoval.cs (100%) rename Trimmer/Rewriters/{ => Statements}/IfElseStmtRemoval.cs (88%) create mode 100644 Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs rename Trimmer/Rewriters/{ => Statements}/SyntaxRewriter.cs (73%) rename Trimmer/Rewriters/{ => Statements}/WhileStmtRemoval.cs (100%) diff --git a/README.md b/README.md index 5e72ffc..a24f850 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 9. struct 10. Assignment expression 11. Initialize out, return statement -12. Method call \ No newline at end of file +12. Method call +13. Trimmer: works for statement \ No newline at end of file diff --git a/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs new file mode 100644 index 0000000..d82e63a --- /dev/null +++ b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen.Trimmer.Rewriters.Expressions +{ + public class BinaryExpRemoval : SyntaxRewriter + { + public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) + { + if (currId++ == id || removeAll) + { + return ParseExpression("1+2").SyntaxTree.GetRoot(); + } + + return base.VisitBinaryExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs new file mode 100644 index 0000000..a3d4a32 --- /dev/null +++ b/Trimmer/Rewriters/Expressions/CastExprRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters.Expressions +{ + public class CastExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitCastExpression(CastExpressionSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitCastExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/AssignStmtRemoval.cs b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs similarity index 74% rename from Trimmer/Rewriters/AssignStmtRemoval.cs rename to Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs index cc0993c..562e9fd 100644 --- a/Trimmer/Rewriters/AssignStmtRemoval.cs +++ b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs @@ -12,16 +12,16 @@ namespace Antigen.Trimmer.Rewriters { - public class AssignStmtRemoval : SyntaxRewriter + public class IdentityNameExprRemoval : SyntaxRewriter { - public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) + public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { if (currId++ == id || removeAll) { return null; } - return base.VisitExpressionStatement(node); + return base.VisitIdentifierName(node); } } } diff --git a/Trimmer/Rewriters/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs similarity index 72% rename from Trimmer/Rewriters/LocalDeclStmtRemoval.cs rename to Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs index 44326be..a5426cf 100644 --- a/Trimmer/Rewriters/LocalDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs @@ -12,16 +12,16 @@ namespace Antigen.Trimmer.Rewriters { - public class LocalDeclStmtRemoval : SyntaxRewriter + public class LiteralExprRemoval : SyntaxRewriter { - public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) + public override SyntaxNode VisitLiteralExpression(LiteralExpressionSyntax node) { if (currId++ == id || removeAll) { return null; } - return base.VisitLocalDeclarationStatement(node); + return base.VisitLiteralExpression(node); } } } diff --git a/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs new file mode 100644 index 0000000..d362b4d --- /dev/null +++ b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters.Expressions +{ + public class MemberAccessExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitMemberAccessExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs b/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs new file mode 100644 index 0000000..8bcb9e4 --- /dev/null +++ b/Trimmer/Rewriters/Expressions/ParenExprRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters.Expressions +{ + public class ParenExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitParenthesizedExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs b/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs new file mode 100644 index 0000000..3814646 --- /dev/null +++ b/Trimmer/Rewriters/Statements/AssignStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class AssignStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) + { + string assignmentExpr = node.ToFullString(); + if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) + { + return base.VisitExpressionStatement(node); + } + + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitExpressionStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/BlockRemoval.cs b/Trimmer/Rewriters/Statements/BlockRemoval.cs new file mode 100644 index 0000000..7785fd0 --- /dev/null +++ b/Trimmer/Rewriters/Statements/BlockRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen.Trimmer.Rewriters.Statements +{ + public class BlockRemoval : SyntaxRewriter + { + public override SyntaxNode VisitBlock(BlockSyntax node) + { + if (currId++ == id || removeAll) + { + return Block(); + } + + return base.VisitBlock(node); + } + } +} diff --git a/Trimmer/Rewriters/DoWhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs similarity index 100% rename from Trimmer/Rewriters/DoWhileStmtRemoval.cs rename to Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs diff --git a/Trimmer/Rewriters/ForStmtRemoval.cs b/Trimmer/Rewriters/Statements/ForStmtRemoval.cs similarity index 100% rename from Trimmer/Rewriters/ForStmtRemoval.cs rename to Trimmer/Rewriters/Statements/ForStmtRemoval.cs diff --git a/Trimmer/Rewriters/IfElseStmtRemoval.cs b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs similarity index 88% rename from Trimmer/Rewriters/IfElseStmtRemoval.cs rename to Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs index 19b613a..f7adbe3 100644 --- a/Trimmer/Rewriters/IfElseStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs @@ -21,6 +21,11 @@ public override SyntaxNode VisitIfStatement(IfStatementSyntax node) return base.VisitIfStatement(node); } + if (currId++ == id || removeAll) + { + return null; + } + return base.VisitIfStatement(node); } } diff --git a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs new file mode 100644 index 0000000..06afebd --- /dev/null +++ b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class LocalDeclStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) + { + string assignmentExpr = node.ToFullString(); + if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) + { + return base.VisitLocalDeclarationStatement(node); + } + + + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitLocalDeclarationStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs new file mode 100644 index 0000000..c9caa67 --- /dev/null +++ b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class MethodDeclStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) + { + if (currId++ == id || removeAll) + { + return null; + } + + return base.VisitMethodDeclaration(node); + } + } +} diff --git a/Trimmer/Rewriters/SyntaxRewriter.cs b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs similarity index 73% rename from Trimmer/Rewriters/SyntaxRewriter.cs rename to Trimmer/Rewriters/Statements/SyntaxRewriter.cs index b99f6c0..68e28a0 100644 --- a/Trimmer/Rewriters/SyntaxRewriter.cs +++ b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -41,5 +42,16 @@ public void UpdateId(int newId) { id = newId; } + + public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia) + { + if (trivia.Kind() == SyntaxKind.SingleLineCommentTrivia || + trivia.Kind() == SyntaxKind.MultiLineCommentTrivia) + { + return default(SyntaxTrivia); + } + + return base.VisitTrivia(trivia); + } } } diff --git a/Trimmer/Rewriters/WhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs similarity index 100% rename from Trimmer/Rewriters/WhileStmtRemoval.cs rename to Trimmer/Rewriters/Statements/WhileStmtRemoval.cs diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index cfdca3d..4661b62 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -4,12 +4,16 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Antigen.Config; using Antigen.Trimmer.Rewriters; +using Antigen.Trimmer.Rewriters.Expressions; +using Antigen.Trimmer.Rewriters.Statements; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -30,99 +34,122 @@ public TestTrimmer(string testFileToTrim, RunOptions runOptions) public void Trim() { - var treeRoot = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + var trimTask = Task.Run(TrimTree); + trimTask.Wait(TimeSpan.FromMinutes(20)); + } + /// + /// Trim the test case. + /// + private void TrimTree() + { + SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + bool trimmedAtleastOne; + int iterId = 1; - //TODO: populate baseline and test envvars: - Dictionary baselineEnvVars = Rsln.BaselineEnvVars; - Dictionary testEnvVars = new Dictionary() - { - {"COMPlus_JitStress", "2" }, - {"COMPlus_JitStressRegs", "0x10000" }, - {"COMPlus_TieredCompilation", "0" } - }; - TestResult reproTestResult = TestResult.Fail; - - //IfElseStmtRemoval ifElse = new IfElseStmtRemoval(); - //ifElse.UpdateId(0); - //var newRoot = ifElse.Visit(treeRoot); - //File.WriteAllText(@"E:\temp\antigen-trimmer\1.trim.g.cs", newRoot.ToFullString()); - - List trimmerList = new List() + do { - new DoWhileStmtRemoval(), - new ForStmtRemoval(), - new WhileStmtRemoval(), - new IfElseStmtRemoval(), - new AssignStmtRemoval(), - new LocalDeclStmtRemoval(), - }; - - // pick category - SyntaxNode recentTree = treeRoot; - int iterId = 0; - foreach (var trimmer in trimmerList) - { - SyntaxNode treeBeforeTrim = recentTree; - - // remove all - Console.Write($"{iterId}. {trimmer.GetType()}"); - - trimmer.RemoveAll(); - SyntaxNode treeAfterTrim = trimmer.Visit(recentTree); + trimmedAtleastOne = false; - //repros = Verify(treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult; + //TODO: populate baseline and test envvars: + Dictionary baselineEnvVars = Rsln.BaselineEnvVars; + Dictionary testEnvVars = new Dictionary() + { + {"COMPlus_JitStress", "2" }, + {"COMPlus_JitStressRegs", "0x80" }, + {"COMPlus_TieredCompilation", "0" } + }; + TestResult reproTestResult = TestResult.Fail; - // compile, execute and repro - if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + List trimmerList = new List() { - // move to next trimmer - recentTree = treeAfterTrim; - Console.WriteLine(" - Success"); - continue; - } - else + // From high to low + + // statements/blocks + new MethodDeclStmtRemoval(), + new BlockRemoval(), + new DoWhileStmtRemoval(), + new ForStmtRemoval(), + new WhileStmtRemoval(), + new IfElseStmtRemoval(), + new AssignStmtRemoval(), + new LocalDeclStmtRemoval(), + + // expressions + //new ParenExprRemoval(), + //new BinaryExpRemoval(), + //new MemberAccessExprRemoval(), + //new LiteralExprRemoval(), + //new IdentityNameExprRemoval(), + //new CastExprRemoval(), + }; + + // pick category + foreach (var trimmer in trimmerList) { - recentTree = treeBeforeTrim; - Console.WriteLine(" - Revert"); - } + SyntaxNode treeBeforeTrim = recentTree; - int noOfNodes = trimmer.TotalVisited; + // remove all + Console.Write($"{iterId}. {trimmer.GetType()}"); - trimmer.Reset(); - trimmer.RemoveOneByOne(); - - int nodeId = 0; - while (nodeId < noOfNodes) - { - Console.Write($"{iterId}. {trimmer.GetType()}, nodeId = {nodeId}"); - trimmer.Reset(); - trimmer.UpdateId(nodeId); - treeAfterTrim = trimmer.Visit(recentTree); + trimmer.RemoveAll(); + SyntaxNode treeAfterTrim = trimmer.Visit(recentTree); // compile, execute and repro - if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + if (trimmer.TotalVisited > 0 && Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) { // move to next trimmer recentTree = treeAfterTrim; - - // We have just removed a node, so decrease nodes count - noOfNodes--; - Console.WriteLine(" - Success"); - + trimmedAtleastOne = true; + continue; } else { recentTree = treeBeforeTrim; + Console.WriteLine(" - Revert"); + } - // Go to next nodeId - nodeId++; + int noOfNodes = trimmer.TotalVisited; - Console.WriteLine(" - Revert"); + trimmer.Reset(); + trimmer.RemoveOneByOne(); + + int nodeId = 0; + int localIterId = 0; + while (nodeId < noOfNodes) + { + Console.Write($"{iterId}. {trimmer.GetType()}, localIterId = {localIterId++}"); + trimmer.Reset(); + trimmer.UpdateId(nodeId); + + treeBeforeTrim = recentTree; + treeAfterTrim = trimmer.Visit(recentTree); + + // compile, execute and repro + if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + { + // move to next trimmer + recentTree = treeAfterTrim; + + // We have just removed a node, so decrease nodes count + noOfNodes--; + + Console.WriteLine(" - Success"); + trimmedAtleastOne = true; + } + else + { + recentTree = treeBeforeTrim; + + // Go to next nodeId + nodeId++; + + Console.WriteLine(" - Revert"); + } } } - } + } while (trimmedAtleastOne); } private List knownDiffs = new List() @@ -170,7 +197,9 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< } } - fileContents.AppendLine(programRootNode.ToFullString()); + string programContents = programRootNode.ToFullString(); + programContents = Regex.Replace(programContents, @"[\r\n]*$", string.Empty, RegexOptions.Multiline); + fileContents.AppendLine(programContents); fileContents.AppendLine("/*"); fileContents.AppendLine($"Got output diff:"); @@ -197,8 +226,11 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine(test); fileContents.AppendLine("*/"); + //TODO: Only if something was visited + string failedFileName = $"{iterId}-lkg"; - string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); + string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round3", $"{ failedFileName}.g.cs"); + //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); From f5221e505d608cff984cb990f96cb7e2ff0634cc Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 25 Jan 2021 00:27:36 -0800 Subject: [PATCH 031/149] working trimmer for binop expresion --- .../Rewriters/Expressions/BinaryExpRemoval.cs | 18 +- .../Rewriters/Expressions/CastExprRemoval.cs | 5 +- .../Expressions/IdentityNameExprRemoval.cs | 2 + .../Expressions/LiteralExprRemoval.cs | 2 + .../Expressions/MemberAccessExprRemoval.cs | 2 + .../Rewriters/Expressions/ParenExprRemoval.cs | 4 +- .../Rewriters/Statements/AssignStmtRemoval.cs | 2 + Trimmer/Rewriters/Statements/BlockRemoval.cs | 7 + .../Statements/DoWhileStmtRemoval.cs | 2 + .../Rewriters/Statements/ForStmtRemoval.cs | 2 + .../Rewriters/Statements/IfElseStmtRemoval.cs | 2 + .../Statements/LocalDeclStmtRemoval.cs | 2 + .../Statements/MethodDeclStmtRemoval.cs | 2 + .../Rewriters/Statements/SyntaxRewriter.cs | 6 +- .../Rewriters/Statements/WhileStmtRemoval.cs | 2 + Trimmer/TestTrimmer.cs | 172 +++++++++++++----- 16 files changed, 187 insertions(+), 45 deletions(-) diff --git a/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs index d82e63a..095856c 100644 --- a/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs +++ b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs @@ -8,19 +8,35 @@ using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Trimmer.Rewriters.Expressions { + public class BinaryExpRemoval : SyntaxRewriter { + private static HashSet s_trimmedExpr = new HashSet(); + + //TODO: Try replacing LHS RHS, just LHS, just RHS. public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { + if (s_trimmedExpr.Contains(node.ToFullString())) + { + return node; + } + if (currId++ == id || removeAll) { - return ParseExpression("1+2").SyntaxTree.GetRoot(); + isAnyNodeVisited = true; + + var left = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(15)); + var right = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(4)); + var trimmedExpr = BinaryExpression(node.Kind(), left, right); + s_trimmedExpr.Add(trimmedExpr.ToFullString()); + return trimmedExpr; } return base.VisitBinaryExpression(node); diff --git a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs index a3d4a32..fb281b3 100644 --- a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs @@ -18,7 +18,10 @@ public override SyntaxNode VisitCastExpression(CastExpressionSyntax node) { if (currId++ == id || removeAll) { - return null; + isAnyNodeVisited = true; + + var expr = (ParenthesizedExpressionSyntax)node.ChildNodes().ToList()[1]; + return VisitParenthesizedExpression(expr); } return base.VisitCastExpression(node); diff --git a/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs index 562e9fd..8a5904d 100644 --- a/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs index a5426cf..fbcbe2e 100644 --- a/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitLiteralExpression(LiteralExpressionSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs index d362b4d..c972212 100644 --- a/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyn { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs b/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs index 8bcb9e4..9c9c341 100644 --- a/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs @@ -18,7 +18,9 @@ public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionS { if (currId++ == id || removeAll) { - return null; + isAnyNodeVisited = true; + + return Visit(node.ChildNodes().ToList()[0]); } return base.VisitParenthesizedExpression(node); diff --git a/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs b/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs index 3814646..cb82d56 100644 --- a/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs @@ -26,6 +26,8 @@ public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax no if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/BlockRemoval.cs b/Trimmer/Rewriters/Statements/BlockRemoval.cs index 7785fd0..24d34be 100644 --- a/Trimmer/Rewriters/Statements/BlockRemoval.cs +++ b/Trimmer/Rewriters/Statements/BlockRemoval.cs @@ -17,8 +17,15 @@ public class BlockRemoval : SyntaxRewriter { public override SyntaxNode VisitBlock(BlockSyntax node) { + if (node.Statements.Count == 0) + { + return node; + } + if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return Block(); } diff --git a/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs index 1b9e515..89d50f1 100644 --- a/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitDoStatement(DoStatementSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/ForStmtRemoval.cs b/Trimmer/Rewriters/Statements/ForStmtRemoval.cs index 1b1752e..2914c43 100644 --- a/Trimmer/Rewriters/Statements/ForStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ForStmtRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitForStatement(ForStatementSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs index f7adbe3..320d21e 100644 --- a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs @@ -23,6 +23,8 @@ public override SyntaxNode VisitIfStatement(IfStatementSyntax node) if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs index 06afebd..2901388 100644 --- a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs @@ -27,6 +27,8 @@ public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatem if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs index c9caa67..023b491 100644 --- a/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/Rewriters/Statements/SyntaxRewriter.cs b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs index 68e28a0..ece2025 100644 --- a/Trimmer/Rewriters/Statements/SyntaxRewriter.cs +++ b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs @@ -16,7 +16,8 @@ public class SyntaxRewriter : CSharpSyntaxRewriter { protected int id = -1; protected int currId = 0; - protected bool removeAll = true; + protected bool removeAll = false; + protected bool isAnyNodeVisited = false; public void RemoveAll() { @@ -33,8 +34,11 @@ public void RemoveOneByOne() /// public int TotalVisited => currId; + public bool IsAnyNodeVisited => isAnyNodeVisited; + public void Reset() { + isAnyNodeVisited = false; currId = 0; } diff --git a/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs index 35a2114..b2cae3f 100644 --- a/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs @@ -18,6 +18,8 @@ public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node) { if (currId++ == id || removeAll) { + isAnyNodeVisited = true; + return null; } diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 4661b62..70f2a7e 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -24,6 +23,7 @@ public class TestTrimmer RunOptions RunOptions; private string _testFileToTrim; private static TestRunner _testRunner; + static int s_iterId = 1; public TestTrimmer(string testFileToTrim, RunOptions runOptions) { @@ -38,18 +38,105 @@ public void Trim() trimTask.Wait(TimeSpan.FromMinutes(20)); } + /// + /// 1. Trim as many statements as possible + /// 2. Trim as many expressions as possible + /// 3. If anything was trimmed, goto 1. + /// + public void TrimTree() + { + bool trimmedAtleastOne = false; + do + { + trimmedAtleastOne |= TrimStatements(); + trimmedAtleastOne |= TrimExpressions(); + + } while (trimmedAtleastOne); + + } + + /// + /// Iterate through all the trimmers and trim the tree using them. + /// If at least one trimmer could trim the tree successfully, rerun all + /// the trimmers until there was no change made to the tree. + /// + /// + public bool TrimStatements() + { + List trimmerList = new List() + { + // From high to low + + // statements/blocks + new MethodDeclStmtRemoval(), + new BlockRemoval(), + new DoWhileStmtRemoval(), + new ForStmtRemoval(), + new WhileStmtRemoval(), + new IfElseStmtRemoval(), + new AssignStmtRemoval(), + new LocalDeclStmtRemoval(), + }; + + bool trimmedAtleastOne = false; + bool trimmedInCurrIter; + + do + { + trimmedInCurrIter = false; + trimmedInCurrIter |= TrimWithTrimmer(trimmerList); + trimmedAtleastOne |= trimmedInCurrIter; + } while (trimmedInCurrIter); + + return trimmedAtleastOne; + } + + /// + /// Iterate through all the trimmers and trim the tree using them. + /// If at least one trimmer could trim the tree successfully, rerun all + /// the trimmers until there was no change made to the tree. + /// + /// + public bool TrimExpressions() + { + List trimmerList = new List() + { + // From high to low + + // expressions + new CastExprRemoval(), + new ParenExprRemoval(), + new BinaryExpRemoval(), + //new MemberAccessExprRemoval(), + //new LiteralExprRemoval(), + //new IdentityNameExprRemoval(), + }; + + bool trimmedAtleastOne = false; + bool trimmedInCurrIter; + + do + { + trimmedInCurrIter = false; + trimmedInCurrIter |= TrimWithTrimmer(trimmerList); + trimmedAtleastOne |= trimmedInCurrIter; + } while (trimmedInCurrIter); + + return trimmedAtleastOne; + } + /// /// Trim the test case. /// - private void TrimTree() + private bool TrimWithTrimmer(List trimmerList) { SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); - bool trimmedAtleastOne; - int iterId = 1; + bool trimmedAtleastOne = false; + bool trimmedInCurrIter; do { - trimmedAtleastOne = false; + trimmedInCurrIter = false; //TODO: populate baseline and test envvars: Dictionary baselineEnvVars = Rsln.BaselineEnvVars; @@ -61,47 +148,41 @@ private void TrimTree() }; TestResult reproTestResult = TestResult.Fail; - List trimmerList = new List() - { - // From high to low - - // statements/blocks - new MethodDeclStmtRemoval(), - new BlockRemoval(), - new DoWhileStmtRemoval(), - new ForStmtRemoval(), - new WhileStmtRemoval(), - new IfElseStmtRemoval(), - new AssignStmtRemoval(), - new LocalDeclStmtRemoval(), - - // expressions - //new ParenExprRemoval(), - //new BinaryExpRemoval(), - //new MemberAccessExprRemoval(), - //new LiteralExprRemoval(), - //new IdentityNameExprRemoval(), - //new CastExprRemoval(), - }; - // pick category foreach (var trimmer in trimmerList) { - SyntaxNode treeBeforeTrim = recentTree; + SyntaxNode treeBeforeTrim = recentTree, treeAfterTrim; // remove all - Console.Write($"{iterId}. {trimmer.GetType()}"); + Console.Write($"{s_iterId}. {trimmer.GetType()}"); - trimmer.RemoveAll(); - SyntaxNode treeAfterTrim = trimmer.Visit(recentTree); + int noOfNodes; + + // For expression, it can be nested, so first count + // total expressions present. + if (trimmer is BinaryExpRemoval) + { + treeAfterTrim = trimmer.Visit(recentTree); + noOfNodes = trimmer.TotalVisited; + trimmer.RemoveAll(); + treeAfterTrim = trimmer.Visit(recentTree); + } + // for statements, count while removing them all. + else + { + trimmer.RemoveAll(); + + treeAfterTrim = trimmer.Visit(recentTree); + noOfNodes = trimmer.TotalVisited; + } // compile, execute and repro - if (trimmer.TotalVisited > 0 && Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + if (trimmer.IsAnyNodeVisited && Verify($"trim{s_iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) { // move to next trimmer recentTree = treeAfterTrim; Console.WriteLine(" - Success"); - trimmedAtleastOne = true; + trimmedInCurrIter = true; continue; } else @@ -110,7 +191,6 @@ private void TrimTree() Console.WriteLine(" - Revert"); } - int noOfNodes = trimmer.TotalVisited; trimmer.Reset(); trimmer.RemoveOneByOne(); @@ -119,7 +199,7 @@ private void TrimTree() int localIterId = 0; while (nodeId < noOfNodes) { - Console.Write($"{iterId}. {trimmer.GetType()}, localIterId = {localIterId++}"); + Console.Write($"{s_iterId}. {trimmer.GetType()}, localIterId = {localIterId++}"); trimmer.Reset(); trimmer.UpdateId(nodeId); @@ -127,15 +207,23 @@ private void TrimTree() treeAfterTrim = trimmer.Visit(recentTree); // compile, execute and repro - if (Verify($"trim{iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + if (trimmer.IsAnyNodeVisited && Verify($"trim{s_iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) { // move to next trimmer recentTree = treeAfterTrim; - // We have just removed a node, so decrease nodes count - noOfNodes--; + if (trimmer is BinaryExpRemoval) + { + nodeId++; + } + else + { + // We have just removed a node, so decrease nodes count + noOfNodes--; + } Console.WriteLine(" - Success"); + trimmedInCurrIter = true; trimmedAtleastOne = true; } else @@ -149,7 +237,9 @@ private void TrimTree() } } } - } while (trimmedAtleastOne); + } while (trimmedInCurrIter); + + return trimmedAtleastOne; } private List knownDiffs = new List() @@ -229,7 +319,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< //TODO: Only if something was visited string failedFileName = $"{iterId}-lkg"; - string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round3", $"{ failedFileName}.g.cs"); + string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round8", $"{ failedFileName}.g.cs"); //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); From 8698430af554e6d8e834145a78313f693d9a46d0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 3 Aug 2021 16:32:20 -0700 Subject: [PATCH 032/149] try-catch-finally --- Config/ConfigOptions.cs | 1 + Program.cs | 65 +++++++++++++++++---------- README.md | 3 +- RoslynTypes.cs | 13 +++++- TestMethod.cs | 99 +++++++++++++++++++++++++++++++++++++++++ Tree/Statements.cs | 1 + Tree/Types.cs | 6 +++ Trimmer/TestTrimmer.cs | 3 +- 8 files changed, 164 insertions(+), 27 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 50ba3b4..9cfe698 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -30,6 +30,7 @@ public class ConfigOptions : OptionsBase public double ForStatementWeight = 0.4; public double DoWhileStatementWeight = 0.2; public double WhileStatementWeight = 0.3; + public double TryCatchFinallyStatementWeight = 0.4; // Type weights public double BooleanWeight = 1; diff --git a/Program.cs b/Program.cs index 878edb8..765226a 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Antigen.Config; using Antigen.Trimmer; @@ -12,43 +13,59 @@ class Program static void Main(string[] args) { - PRNG.Initialize(RunOptions.Seed); + try + { + PRNG.Initialize(RunOptions.Seed); - RunOptions.CoreRun = args[0]; + RunOptions.CoreRun = args[0]; - // trimmer - if (args.Length > 1) - { - string testCaseToTrim = args[1]; - TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, RunOptions); - testTrimmer.Trim(); - return; - } + // trimmer + if (args.Length > 1) + { + string testCaseToTrim = args[1]; + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, RunOptions); + testTrimmer.Trim(); + return; + } - int testId = 1; - Dictionary stats = new Dictionary() + int testId = 1; + Dictionary stats = new Dictionary() { { TestResult.CompileError, 0 }, { TestResult.Fail, 0 }, {TestResult.OutputMismatch, 0 }, {TestResult.Pass, 0 }, }; - while (true) - { - TestCase testCase = new TestCase(testId, RunOptions); - testCase.Generate(); - TestResult result = testCase.Verify(); - stats[result]++; - Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. "); - if ((testId % 100) == 0) + while (true) { - foreach (var st in stats) + TestCase testCase = new TestCase(testId, RunOptions); + testCase.Generate(); + TestResult result = testCase.Verify(); + stats[result]++; + Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. "); + if ((testId % 100) == 0) { - Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); + foreach (var st in stats) + { + Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); + } } + Console.WriteLine(); + testId++; + GC.Collect(); } - Console.WriteLine(); - testId++; + } catch (OutOfMemoryException oom) + { + Console.WriteLine(oom.Message); + var myProcess = System.Diagnostics.Process.GetCurrentProcess(); + Console.WriteLine($" Physical memory usage : {myProcess.WorkingSet64}"); + Console.WriteLine($" Base priority : {myProcess.BasePriority}"); + Console.WriteLine($" Priority class : {myProcess.PriorityClass}"); + Console.WriteLine($" User processor time : {myProcess.UserProcessorTime}"); + Console.WriteLine($" Privileged processor time : {myProcess.PrivilegedProcessorTime}"); + Console.WriteLine($" Total processor time : {myProcess.TotalProcessorTime}"); + Console.WriteLine($" Paged system memory size : {myProcess.PagedSystemMemorySize64}"); + Console.WriteLine($" Paged memory size : {myProcess.PagedMemorySize64}"); } } } diff --git a/README.md b/README.md index a24f850..7f701a9 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 10. Assignment expression 11. Initialize out, return statement 12. Method call -13. Trimmer: works for statement \ No newline at end of file +13. Trimmer: works for statement +14. try-catch-finally \ No newline at end of file diff --git a/RoslynTypes.cs b/RoslynTypes.cs index 4ac94c8..baa7365 100644 --- a/RoslynTypes.cs +++ b/RoslynTypes.cs @@ -17,7 +17,7 @@ public class Rsln internal static readonly Dictionary BaselineEnvVars = new Dictionary() { { "COMPlus_JITMinOpts", "1" }, - { "COMPlus_TieredCompilation" , "0" } + //{ "COMPlus_TieredCompilation" , "0" } }; internal static readonly Dictionary CommonTestEnvVars = new Dictionary() @@ -26,10 +26,21 @@ public class Rsln { "COMPlus_TieredCompilation" , "0" } }; + // Also other flags like turning off certain feature like FinallyCloning=0, etc. // Use other combination from https://github.com/dotnet/runtime/blob/5a6c21cb6285a3c110f0048d9bf657042ea4ca10/src/tests/Common/testenvironment.proj // groups / arch: https://github.com/dotnet/runtime/blob/f8a83c898f18e3ebcd7c0ddd2e1773d8a771b346/eng/pipelines/common/templates/runtimes/run-test-job.yml internal static readonly List TestEnvVars = new List() { + //new ComplusVariableGroup("jitstress", new(){ + // { "JitStress", "1"}, + // { "JitStress", "2"}, + //}), + + //new ComplusVariableGroup("jitstressregs", new(){ + // { "JitStress", "1"}, + // { "JitStress", "2"}, + //}), + new ComplusVariableGroup("jitstress1", new () { { "COMPlus_JitStress", "1" }, diff --git a/TestMethod.cs b/TestMethod.cs index 2c016b1..03907c6 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -517,6 +517,105 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); return Annotate(ReturnStatement(returnExpr), "Return"); } + case StmtKind.TryCatchFinallyStatement: + + //TODO-config: Add MaxDepth in config + int catchCounts = PRNG.Next(0, 3); + + //TODO-config: Add finally weight in config + // If there are no catch, then definitely add finally, otherwise skip it. + bool hasFinally = catchCounts == 0 || PRNG.Decide(0.5); + IList tryBody = new List(); + IList catchClauses = new List(); + IList finallyBody = new List(); + + Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(tryScope); + + //TODO-config: Add MaxDepth in config + int tryStmtCount = PRNG.Next(1, s_maxStatements); + for (int i = 0; i < tryStmtCount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + tryBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'try' body scope + + var allExceptions = Tree.ValueType.AllExceptions; + var caughtExceptions = new List(); + for (int catchId = 0; catchId < catchCounts; catchId++) + { + var exceptionToCatch = allExceptions[PRNG.Next(allExceptions.Count)]; + allExceptions.Remove(exceptionToCatch); + + // If we already generated a catch-clause of superclass, skip remaining catch clauses. + if (caughtExceptions.Any(x => exceptionToCatch.IsSubclassOf(x))) + { + break; + } + caughtExceptions.Add(exceptionToCatch); + + //TODO-config: Add MaxDepth in config + int catchStmtCount = PRNG.Next(1, s_maxStatements / 2); + IList catchBody = new List(); + + Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(catchScope); + + //TODO-config: Add MaxDepth in config + for (int i = 0; i < catchStmtCount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + catchBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'catch' body scope + + catchClauses.Add(CatchClause(CatchDeclaration(IdentifierName(exceptionToCatch.Name)), null, Block(catchBody))); + } + + if (hasFinally) + { + Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(finallyScope); + + //TODO-config: Add MaxDepth in config + int finallyStmtCount = PRNG.Next(1, s_maxStatements); + for (int i = 0; i < finallyStmtCount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + finallyBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'finally' body scope + } + + return Annotate(TryStatement(Block(tryBody), new SyntaxList(catchClauses), FinallyClause(Block(finallyBody))), "TryCatchFinally"); default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 276cbb9..2632403 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -9,6 +9,7 @@ public enum StmtKind DoWhileStatement, WhileStatement, ReturnStatement, + TryCatchFinallyStatement, //FunctionCallStatement, } diff --git a/Tree/Types.cs b/Tree/Types.cs index da5877f..ef56a25 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -226,6 +226,12 @@ public string VariableNameHint() } } + public static List AllExceptions => + typeof(Exception).Assembly.GetTypes() + .Where(x => x.IsSubclassOf(typeof(Exception))) + .Where(n => n.FullName.StartsWith("System.") && n.FullName.LastIndexOf(".") == 6) + .ToList(); + public override string ToString() { if (PrimitiveType != Primitive.Struct) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 70f2a7e..6e69f52 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -69,6 +69,7 @@ public bool TrimStatements() // statements/blocks new MethodDeclStmtRemoval(), + new StructDeclStmtRemoval(), new BlockRemoval(), new DoWhileStmtRemoval(), new ForStmtRemoval(), @@ -319,7 +320,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< //TODO: Only if something was visited string failedFileName = $"{iterId}-lkg"; - string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round8", $"{ failedFileName}.g.cs"); + string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round9", $"{ failedFileName}.g.cs"); //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); From 581218875af8feaa34da44a333871cf84ff6bd21 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 4 Aug 2021 13:16:28 -0700 Subject: [PATCH 033/149] swich-case --- Config/ConfigOptions.cs | 1 + Helpers/Expressions.cs | 11 +++ README.md | 3 +- TestCase.cs | 2 +- TestClass.cs | 4 +- TestMethod.cs | 206 ++++++++++++++++++++++++++++------------ Tree/Statements.cs | 1 + 7 files changed, 161 insertions(+), 67 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 9cfe698..f21e6ce 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -31,6 +31,7 @@ public class ConfigOptions : OptionsBase public double DoWhileStatementWeight = 0.2; public double WhileStatementWeight = 0.3; public double TryCatchFinallyStatementWeight = 0.4; + public double SwitchStatementWeight = 0.1; // Type weights public double BooleanWeight = 1; diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index ca0b9b4..e92f974 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -52,5 +52,16 @@ public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueT SyntaxKind.SimpleMemberAccessExpression, IdentifierName("MethodImplOptions"), IdentifierName("NoInlining"))))))))); + + /// + /// Converts a to . + /// + /// + /// + /// + public static SyntaxList ToSyntaxList(this IList list) where T : SyntaxNode + { + return new SyntaxList(list); + } } } diff --git a/README.md b/README.md index 7f701a9..992df42 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 11. Initialize out, return statement 12. Method call 13. Trimmer: works for statement -14. try-catch-finally \ No newline at end of file +14. try-catch-finally +15. switch-case \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 2b21829..eeea7d2 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -92,7 +92,7 @@ public void Generate() ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); testCaseRoot = CompilationUnit() - .WithUsings(new SyntaxList(usingDirective)) + .WithUsings(usingDirective.ToSyntaxList()) .WithMembers(new SyntaxList(klass)).NormalizeWhitespace(); } diff --git a/TestClass.cs b/TestClass.cs index d64e971..0c42fec 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -105,7 +105,7 @@ public ClassDeclarationSyntax Generate() PopScope(); return ClassDeclaration(ClassName) - .WithMembers(new SyntaxList(classMembers)) + .WithMembers(classMembers.ToSyntaxList()) .WithModifiers(new SyntaxTokenList(Token(SyntaxKind.PublicKeyword))); } @@ -168,7 +168,7 @@ private List GenerateStructs() fieldsMetadata.Add(new StructField(fieldType, fieldName)); } - return (structDeclaration.WithMembers(new SyntaxList(fieldsTree)), fieldsMetadata); + return (structDeclaration.WithMembers(fieldsTree.ToSyntaxList()), fieldsMetadata); } return structs; diff --git a/TestMethod.cs b/TestMethod.cs index 03907c6..83b4463 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -518,61 +518,21 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(ReturnStatement(returnExpr), "Return"); } case StmtKind.TryCatchFinallyStatement: - - //TODO-config: Add MaxDepth in config - int catchCounts = PRNG.Next(0, 3); - - //TODO-config: Add finally weight in config - // If there are no catch, then definitely add finally, otherwise skip it. - bool hasFinally = catchCounts == 0 || PRNG.Decide(0.5); - IList tryBody = new List(); - IList catchClauses = new List(); - IList finallyBody = new List(); - - Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(tryScope); - - //TODO-config: Add MaxDepth in config - int tryStmtCount = PRNG.Next(1, s_maxStatements); - for (int i = 0; i < tryStmtCount; i++) { - StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) - { - cur = StmtKind.VariableDeclaration; - } - else - { - cur = GetASTUtils().GetRandomStatemet(); - } - tryBody.Add(StatementHelper(cur, depth + 1)); - } - PopScope(); // pop 'try' body scope - - var allExceptions = Tree.ValueType.AllExceptions; - var caughtExceptions = new List(); - for (int catchId = 0; catchId < catchCounts; catchId++) - { - var exceptionToCatch = allExceptions[PRNG.Next(allExceptions.Count)]; - allExceptions.Remove(exceptionToCatch); - - // If we already generated a catch-clause of superclass, skip remaining catch clauses. - if (caughtExceptions.Any(x => exceptionToCatch.IsSubclassOf(x))) - { - break; - } - caughtExceptions.Add(exceptionToCatch); + int catchCounts = PRNG.Next(0, 3); - //TODO-config: Add MaxDepth in config - int catchStmtCount = PRNG.Next(1, s_maxStatements / 2); - IList catchBody = new List(); + //TODO-config: Add finally weight in config + // If there are no catch, then definitely add finally, otherwise skip it. + bool hasFinally = catchCounts == 0 || PRNG.Decide(0.5); + IList tryBody = new List(); - Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(catchScope); + Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(tryScope); //TODO-config: Add MaxDepth in config - for (int i = 0; i < catchStmtCount; i++) + int tryStmtCount = PRNG.Next(1, s_maxStatements); + for (int i = 0; i < tryStmtCount; i++) { StmtKind cur; //TODO-config: Add MaxDepth in config @@ -584,21 +544,133 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { cur = GetASTUtils().GetRandomStatemet(); } - catchBody.Add(StatementHelper(cur, depth + 1)); + tryBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'catch' body scope + PopScope(); // pop 'try' body scope - catchClauses.Add(CatchClause(CatchDeclaration(IdentifierName(exceptionToCatch.Name)), null, Block(catchBody))); - } + IList catchClauses = new List(); + var allExceptions = Tree.ValueType.AllExceptions; + var caughtExceptions = new List(); + for (int catchId = 0; catchId < catchCounts; catchId++) + { + var exceptionToCatch = allExceptions[PRNG.Next(allExceptions.Count)]; + allExceptions.Remove(exceptionToCatch); + + // If we already generated a catch-clause of superclass, skip remaining catch clauses. + if (caughtExceptions.Any(x => exceptionToCatch.IsSubclassOf(x))) + { + break; + } + caughtExceptions.Add(exceptionToCatch); + + //TODO-config: Add MaxDepth in config + int catchStmtCount = PRNG.Next(1, s_maxStatements / 2); + IList catchBody = new List(); + + Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(catchScope); - if (hasFinally) + //TODO-config: Add MaxDepth in config + for (int i = 0; i < catchStmtCount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + catchBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'catch' body scope + + catchClauses.Add(CatchClause(CatchDeclaration(IdentifierName(exceptionToCatch.Name)), null, Block(catchBody))); + } + + IList finallyBody = new List(); + if (hasFinally) + { + Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(finallyScope); + + //TODO-config: Add MaxDepth in config + int finallyStmtCount = PRNG.Next(1, s_maxStatements); + for (int i = 0; i < finallyStmtCount; i++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + finallyBody.Add(StatementHelper(cur, depth + 1)); + } + PopScope(); // pop 'finally' body scope + } + + return Annotate(TryStatement(Block(tryBody), catchClauses.ToSyntaxList(), FinallyClause(Block(finallyBody))), "TryCatchFinally"); + } + case StmtKind.SwitchStatement: { - Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(finallyScope); + //TODO-config: Add CaseCount in config + int caseCount = PRNG.Next(2, 10); - //TODO-config: Add MaxDepth in config - int finallyStmtCount = PRNG.Next(1, s_maxStatements); - for (int i = 0; i < finallyStmtCount; i++) + Primitive switchType = new Primitive[] { Primitive.Int, Primitive.Long, Primitive.Char, Primitive.String }[PRNG.Next(4)]; + Tree.ValueType switchExprType = Tree.ValueType.ForPrimitive(switchType); + ExprKind switchExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(switchType); + ExpressionSyntax switchExpr = ExprHelper(switchExprKind, switchExprType, 0); + IList listOfCases = new List(); + + // Generate each cases + for (int i = 0; i < caseCount; i++) + { + Scope caseScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(caseScope); + + //TODO-config: Add no. of case statemets in config + // Generate statements within each cases + int caseStmtCount = PRNG.Next(1, 3); + IList caseBody = new List(); + for (int j = 0; j < caseStmtCount; j++) + { + StmtKind cur; + //TODO-config: Add MaxDepth in config + if (depth >= 2) + { + cur = StmtKind.VariableDeclaration; + } + else + { + cur = GetASTUtils().GetRandomStatemet(); + } + caseBody.Add(StatementHelper(cur, depth + 1)); + } + caseBody.Add(BreakStatement()); + PopScope(); // pop 'case' body scope + + listOfCases.Add(SwitchSection() + .WithLabels( + SingletonList( + CaseSwitchLabel( + ExprHelper(ExprKind.LiteralExpression, switchExprType, 0)))) + .WithStatements(caseBody.ToSyntaxList())); + } + + // Generate default + var defaultScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); + PushScope(defaultScope); + + // Generate statements within default + int defaultStmtCount = PRNG.Next(1, 3); + IList defaultBody = new List(); + for (int j = 0; j < defaultStmtCount; j++) { StmtKind cur; //TODO-config: Add MaxDepth in config @@ -610,12 +682,20 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { cur = GetASTUtils().GetRandomStatemet(); } - finallyBody.Add(StatementHelper(cur, depth + 1)); + defaultBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'finally' body scope - } + defaultBody.Add(BreakStatement()); + PopScope(); // pop 'default' body scope + + listOfCases.Add( + SwitchSection() + .WithLabels( + SingletonList( + DefaultSwitchLabel())) + .WithStatements(defaultBody.ToSyntaxList())); - return Annotate(TryStatement(Block(tryBody), new SyntaxList(catchClauses), FinallyClause(Block(finallyBody))), "TryCatchFinally"); + return Annotate(SwitchStatement(switchExpr).WithSections(listOfCases.ToSyntaxList()), "SwitchCase"); + } default: Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 2632403..0de7ff9 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -10,6 +10,7 @@ public enum StmtKind WhileStatement, ReturnStatement, TryCatchFinallyStatement, + SwitchStatement, //FunctionCallStatement, } From ea213015b02d6b6cf403aa06185deb65f1f9ba57 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 5 Aug 2021 23:47:39 -0700 Subject: [PATCH 034/149] Switches: Complus_ environment variables --- Helpers/RslnUtilities.cs | 71 ++++++++++ Helpers/TestRunner.cs | 2 +- Program.cs | 14 +- README.md | 3 +- RoslynTypes.cs | 150 ---------------------- Switches.cs | 271 +++++++++++++++++++++++++++++++++++++++ TestCase.cs | 137 +++++++------------- 7 files changed, 398 insertions(+), 250 deletions(-) create mode 100644 Helpers/RslnUtilities.cs delete mode 100644 RoslynTypes.cs create mode 100644 Switches.cs diff --git a/Helpers/RslnUtilities.cs b/Helpers/RslnUtilities.cs new file mode 100644 index 0000000..5035875 --- /dev/null +++ b/Helpers/RslnUtilities.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; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen +{ + public class RslnUtilities + { + + public static SyntaxTree GetValidSyntaxTree(SyntaxNode treeRoot, bool doValidation = true) + { + SyntaxTree validTree = CSharpSyntaxTree.ParseText(treeRoot.ToFullString()); + +#if DEBUG + if (doValidation) + { + SyntaxTree syntaxTree = treeRoot.SyntaxTree; + FindTreeDiff(validTree.GetRoot(), syntaxTree.GetRoot()); + } +#else + // In release, make sure that we didn't end up generating wrong syntax tree, + // hence parse the text to reconstruct the tree. +#endif + return validTree; + } + + /// + /// Method to find diff of generated tree vs. roslyn generated tree by parsing the + /// generated code. + /// + /// + /// + private static void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) + { + if ((expected is LiteralExpressionSyntax) || (actual is LiteralExpressionSyntax)) + { + // ignore + return; + } + + if (!expected.IsEquivalentTo(actual)) + { + var expectedChildNodes = expected.ChildNodes().ToArray(); + var actualChildNodes = actual.ChildNodes().ToArray(); + + int expectedCount = expectedChildNodes.Length; + int actualCount = actualChildNodes.Length; + if (expectedCount != actualCount) + { + Debug.Assert(false, $"Child nodes mismatch. Expected= {expected}, Actual= {actual}"); + return; + } + for (int ch = 0; ch < expectedCount; ch++) + { + FindTreeDiff(expectedChildNodes[ch], actualChildNodes[ch]); + } + return; + } + } + } +} diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 9be8347..ea0519a 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -53,7 +53,7 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, references, Rsln.CompileOptions); + var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, references, Switches.CompileOptions); string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{assemblyName}.exe"); using (var ms = new MemoryStream()) diff --git a/Program.cs b/Program.cs index 765226a..c9e150f 100644 --- a/Program.cs +++ b/Program.cs @@ -16,7 +16,7 @@ static void Main(string[] args) try { PRNG.Initialize(RunOptions.Seed); - + Switches.Initialize(); RunOptions.CoreRun = args[0]; // trimmer @@ -30,12 +30,12 @@ static void Main(string[] args) int testId = 1; Dictionary stats = new Dictionary() - { - { TestResult.CompileError, 0 }, - { TestResult.Fail, 0 }, - {TestResult.OutputMismatch, 0 }, - {TestResult.Pass, 0 }, - }; + { + { TestResult.CompileError, 0 }, + { TestResult.Fail, 0 }, + {TestResult.OutputMismatch, 0 }, + {TestResult.Pass, 0 }, + }; while (true) { TestCase testCase = new TestCase(testId, RunOptions); diff --git a/README.md b/README.md index 992df42..34eda94 100644 --- a/README.md +++ b/README.md @@ -16,4 +16,5 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 12. Method call 13. Trimmer: works for statement 14. try-catch-finally -15. switch-case \ No newline at end of file +15. switch-case +16. Environment variables list diff --git a/RoslynTypes.cs b/RoslynTypes.cs deleted file mode 100644 index baa7365..0000000 --- a/RoslynTypes.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.VisualBasic.CompilerServices; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Antigen -{ - public class Rsln - { - internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); - - internal static readonly Dictionary BaselineEnvVars = new Dictionary() - { - { "COMPlus_JITMinOpts", "1" }, - //{ "COMPlus_TieredCompilation" , "0" } - }; - - internal static readonly Dictionary CommonTestEnvVars = new Dictionary() - { - { "COMPlus_JITMinOpts", "0" }, - { "COMPlus_TieredCompilation" , "0" } - }; - - // Also other flags like turning off certain feature like FinallyCloning=0, etc. - // Use other combination from https://github.com/dotnet/runtime/blob/5a6c21cb6285a3c110f0048d9bf657042ea4ca10/src/tests/Common/testenvironment.proj - // groups / arch: https://github.com/dotnet/runtime/blob/f8a83c898f18e3ebcd7c0ddd2e1773d8a771b346/eng/pipelines/common/templates/runtimes/run-test-job.yml - internal static readonly List TestEnvVars = new List() - { - //new ComplusVariableGroup("jitstress", new(){ - // { "JitStress", "1"}, - // { "JitStress", "2"}, - //}), - - //new ComplusVariableGroup("jitstressregs", new(){ - // { "JitStress", "1"}, - // { "JitStress", "2"}, - //}), - - new ComplusVariableGroup("jitstress1", new () - { - { "COMPlus_JitStress", "1" }, - }), - new ComplusVariableGroup("jitstress1_tiered", new () - { - { "COMPlus_JitStress", "1" }, - { "COMPlus_TieredCompilation", "1" }, - }), - new ComplusVariableGroup("jitstress2", new () - { - { "COMPlus_JitStress", "2" }, - }), - new ComplusVariableGroup("jitstress2_tiered", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_TieredCompilation", "1" }, - }), - new ComplusVariableGroup("jitstressregs1", new () - { - { "COMPlus_JitStressRegs", "1" }, - }), - new ComplusVariableGroup("jitstressregs2", new () - { - { "COMPlus_JitStressRegs", "2" }, - }), - new ComplusVariableGroup("jitstressregs3", new () - { - { "COMPlus_JitStressRegs", "3" }, - }), - new ComplusVariableGroup("jitstressregs4", new () - { - { "COMPlus_JitStressRegs", "4" }, - }), - new ComplusVariableGroup("jitstressregs8", new () - { - { "COMPlus_JitStressRegs", "8" }, - }), - new ComplusVariableGroup("jitstressregs10", new () - { - { "COMPlus_JitStressRegs", "0x10" }, - }), - new ComplusVariableGroup("jitstressregs80", new () - { - { "COMPlus_JitStressRegs", "0x80" }, - }), - new ComplusVariableGroup("jitstressregs1000", new () - { - { "COMPlus_JitStressRegs", "0x10000" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs1", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "1" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs2", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "2" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs3", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "3" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs4", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "4" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs8", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "8" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs0x10", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "0x10" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs0x80", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "0x80" }, - }), - new ComplusVariableGroup("jitstress2_jitstressregs0x1000", new () - { - { "COMPlus_JitStress", "2" }, - { "COMPlus_JitStressRegs", "0x10000" }, - }), - }; - } - - public class ComplusVariableGroup - { - public string Name { get; private set; } - public Dictionary Vars { get; set; } - - internal ComplusVariableGroup(string name, Dictionary vars) - { - Name = name; - Vars = vars; - } - } - - -} diff --git a/Switches.cs b/Switches.cs new file mode 100644 index 0000000..44bf1e6 --- /dev/null +++ b/Switches.cs @@ -0,0 +1,271 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.VisualBasic.CompilerServices; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + internal class ComplusEnvVarGroup + { + public string Name { get; } + public List EnvVariables { get; } + + /// + /// Weights of individual EnvVars present in this group. + /// + private readonly List> variableWeights; + + public ComplusEnvVarGroup(string name) + { + Name = name; + EnvVariables = new List(); + variableWeights = new List>(); + } + + public void AddVariable(ComplusEnvVar variable) + { + EnvVariables.Add(variable); + variableWeights.Add(new Weights(variable, variable.Weight)); + } + + public ComplusEnvVar GetRandomVariable() + { + return PRNG.WeightedChoice(variableWeights); + } + + public ComplusEnvVar GetVariable(string name) + { + return EnvVariables.First(envVar => envVar.Name == name); + } + } + + internal class ComplusEnvVar + { + public string Name { get; } + public string[] Values { get; } + public double Weight { get; } + + public ComplusEnvVar(string name, string[] values, double weight) + { + Name = name; + Values = values; + Weight = weight; + } + + public override string ToString() + { + return $"COMPlus_{Name}=[{string.Join(",", Values)}]"; + } + + public override bool Equals(object obj) + { + if (obj is not ComplusEnvVar otherObj) + { + return false; + } + + return otherObj.Name == Name; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + } + + public class Switches + { + + private static ComplusEnvVarGroup s_baselineGroup; + private static ComplusEnvVarGroup s_defaultGroup; + private static ComplusEnvVarGroup s_jitStressGroup; + private static ComplusEnvVarGroup s_jitStressRegsGroup; + private static ComplusEnvVarGroup s_hardwareGroup; + private static ComplusEnvVarGroup s_commonVarGroup; + + private static readonly string[] s_onOffSwitch = new string[] { "0", "1" }; + + public static void Initialize() + { + // Populate Baseline + s_baselineGroup = new ComplusEnvVarGroup("Baseline"); + s_baselineGroup.AddVariable(new ComplusEnvVar("JITMinOpts", new string[] { "1" }, 1.0)); + s_baselineGroup.AddVariable(new ComplusEnvVar("TieredCompilation", new string[] { "1" }, 1.0)); + + // Populate Common + s_commonVarGroup = new ComplusEnvVarGroup("Common"); + s_commonVarGroup.AddVariable(new ComplusEnvVar("JITMinOpts", new string[] { "0" }, 1.0)); + s_commonVarGroup.AddVariable(new ComplusEnvVar("TieredCompilation", new string[] { "0" }, 1.0)); + + // Default group + s_defaultGroup = new ComplusEnvVarGroup("Default"); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitCloneLoops", s_onOffSwitch, 0.04)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoops", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoopAdaptive", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoopMinBlockWeight", new string[] { "0", "1", "2", "10", "20" }, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoubleAlign", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableDevirtualization", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableLateDevirtualization", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitForceFallback", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JITInlineDepth", new string[] { "0", "1", "2", "10", "20" }, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCMOV", s_onOffSwitch, 0.04)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCSE", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCSE2", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoForceFallback", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoHoist", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoInline", s_onOffSwitch, 0.04)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoMemoryBarriers", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoStructPromotion", new string[] { "0", "1", "2" }, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoUnroll", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackAllocToLocalSize", new string[] { "0", "1", "2", "4", "10", "16", "100"}, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitSkipArrayBoundCheck", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitSlowDebugChecksEnabled", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitSplitFunctionSize", new string[] { "0", "1", "2", "4", "10", "16", "100" }, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackChecks", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("InjectFault", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoRngChks", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableNoWayAssert", s_onOffSwitch, 0.01)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitAggressiveInlining", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitMaxLocalsToTrack", new string[] { "0", "0x10", "0x400", "0x800", "0x1000"}, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoAssertionProp", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoCopyProp", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoEarlyProp", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoLoopHoisting", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoLoopInversion", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoRangeAnalysis", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoRedundantBranchOpts", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoSsa", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoValueNumber", s_onOffSwitch, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeat", new string[] { "*" }, 0.05)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeatCount", new string[] { "1", "2", "5" }, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("TailCallLoopOpt", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("FastTailCalls", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableFinallyCloning", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableRemoveEmptyTry", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableGuardedDevirtualization", s_onOffSwitch, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitExpandCallsEarly", s_onOffSwitch, 0.03)); + + // JitStress + s_jitStressGroup = new ComplusEnvVarGroup("JitStress"); + s_jitStressGroup.AddVariable(new ComplusEnvVar("JitStress", new string[] { "0", "1", "2" }, 0.04)); + s_jitStressGroup.AddVariable(new ComplusEnvVar("TailcallStress", s_onOffSwitch, 0.02)); + + // JitStressRegs + s_jitStressRegsGroup = new ComplusEnvVarGroup("JitStressRegs"); + s_jitStressRegsGroup.AddVariable(new ComplusEnvVar("JitStressRegs", new string[] { "0", "1", "2", "3", "4", "8", "0x10", "0x80", "0x1000" }, 0.04)); + + // Hardware + s_hardwareGroup = new ComplusEnvVarGroup("Hardware"); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAES", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAVX", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAVX2", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableBMI1", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableBMI2", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableFMA", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableHWIntrinsic", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableIncompleteISAClass", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableLZCNT", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnablePCLMULQDQ", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnablePOPCNT", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE2", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE3", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE3_4", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE41", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE42", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSSE3", s_onOffSwitch, 0.02)); + s_hardwareGroup.AddVariable(new ComplusEnvVar("FeatureSIMD", s_onOffSwitch, 0.02)); + } + + /// + /// Returns baseline variables + /// + /// + public static Dictionary BaseLineVars() + { + var envVars = new Dictionary(); + foreach (var variable in s_baselineGroup.EnvVariables) + { + envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; + } + return envVars; + } + + /// + /// Returns test variables + /// + /// + public static Dictionary TestVars() + { + var envVars = new Dictionary(); + + // common variables + foreach (var variable in s_commonVarGroup.EnvVariables) + { + envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; + } + + // default variables + var usedEnvVars = new HashSet(); + //TODO: config no. of variables to pick + var defaultVariablesCount = PRNG.Next(1, 8); + for (var i = 0; i < defaultVariablesCount; i++) + { + ComplusEnvVar envVar; + + // Avoid duplicate variables + do + { + envVar = s_defaultGroup.GetRandomVariable(); + } while (!usedEnvVars.Add(envVar.Name)); + + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + + + // 30% of time add JitStress flag + if (PRNG.Decide(0.3)) + { + var envVar = s_jitStressGroup.GetRandomVariable(); + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + + // 30% of time add JitStressRegs flag + if (PRNG.Decide(0.3)) + { + var envVar = s_jitStressRegsGroup.GetRandomVariable(); + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + + // 20% of time add Hardware flag + if (PRNG.Decide(0.2)) + { + usedEnvVars = new HashSet(); + //TODO: config no. of variables to pick + var hardwareVariablesCount = PRNG.Next(1, 5); + for (var i = 0; i < hardwareVariablesCount; i++) + { + ComplusEnvVar envVar; + + // Avoid duplicate variables + do + { + envVar = s_hardwareGroup.GetRandomVariable(); + } while (!usedEnvVars.Add(envVar.Name)); + + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + } + + return envVars; + } + + internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); + } + +} diff --git a/TestCase.cs b/TestCase.cs index eeea7d2..5c816da 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using System.Runtime.CompilerServices; using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -98,21 +99,13 @@ public void Generate() public TestResult Verify() { -#if DEBUG - SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; - SyntaxTree expectedTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); - FindTreeDiff(expectedTree.GetRoot(), syntaxTree.GetRoot()); -#else - // In release, make sure that we didn't end up generating wrong syntax tree, - // hence parse the text to reconstruct the tree. + SyntaxTree syntaxTree = RslnUtilities.GetValidSyntaxTree(testCaseRoot); - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(testCaseRoot.ToFullString()); -#endif - - StringBuilder fileContents = new StringBuilder(); CompileResult compileResult = TestRunner.Compile(syntaxTree, Name); if (compileResult.AssemblyFullPath == null) { + StringBuilder fileContents = new StringBuilder(); + fileContents.AppendLine(testCaseRoot.ToFullString()); fileContents.AppendLine("/*"); fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); @@ -133,21 +126,11 @@ public TestResult Verify() // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); //} - string baseline = TestRunner.Execute(compileResult, Rsln.BaselineEnvVars); + var baselineVariables = Switches.BaseLineVars(); + var testVariables = Switches.TestVars(); - var selectedVars = Rsln.TestEnvVars[PRNG.Next(Rsln.TestEnvVars.Count)].Vars; - var testEnvVariables = new Dictionary(); - foreach (var commonVars in Rsln.CommonTestEnvVars) - { - testEnvVariables.Add(commonVars.Key, commonVars.Value); - } - foreach (var selectedVar in selectedVars) - { - // override the COMPlus_TieredCompilation variable - testEnvVariables[selectedVar.Key] = selectedVar.Value; - } - - string test = TestRunner.Execute(compileResult, testEnvVariables); + string baseline = TestRunner.Execute(compileResult, baselineVariables); + string test = TestRunner.Execute(compileResult, testVariables); if (baseline == test) { @@ -172,43 +155,47 @@ public TestResult Verify() } } - fileContents.AppendLine(testCaseRoot.ToFullString()); - fileContents.AppendLine("/*"); - - if (isKnownError) - { - fileContents.AppendLine($"Got known error mismatch:"); - } - else - { - fileContents.AppendLine($"Got output diff:"); - } - fileContents.AppendLine("--------- Baseline --------- "); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - foreach (var envVars in Rsln.BaselineEnvVars) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - fileContents.AppendLine(); - fileContents.AppendLine(baseline); - - fileContents.AppendLine("--------- Test --------- "); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - foreach (var envVars in testEnvVariables) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - fileContents.AppendLine(); - fileContents.AppendLine(test); - fileContents.AppendLine("*/"); - //TODO- for now, delete known error files if (!isKnownError) { + StringBuilder fileContents = new StringBuilder(); + fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVariables.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + fileContents.AppendLine($"// TestVars: {string.Join("|", testVariables.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + fileContents.AppendLine("//"); + fileContents.AppendLine(testCaseRoot.ToFullString()); + fileContents.AppendLine("/*"); + + if (isKnownError) + { + fileContents.AppendLine($"Got known error mismatch:"); + } + else + { + fileContents.AppendLine($"Got output diff:"); + } + fileContents.AppendLine("--------- Baseline ---------"); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in baselineVariables) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); + fileContents.AppendLine(baseline); + + fileContents.AppendLine("--------- Test ---------"); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in testVariables) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + fileContents.AppendLine(); + fileContents.AppendLine(test); + fileContents.AppendLine("*/"); + string failedFileName = $"{Name}-{(isKnownError ? "known-error" : "fail")}"; string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); @@ -230,38 +217,6 @@ public TestResult Verify() } } - /// - /// Method to find diff of generated tree vs. roslyn generated tree by parsing the - /// generated code. - /// - /// - /// - private void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) - { - if ((expected is LiteralExpressionSyntax) || (actual is LiteralExpressionSyntax)) - { - // ignore - return; - } - if (!expected.IsEquivalentTo(actual)) - { - var expectedChildNodes = expected.ChildNodes().ToArray(); - var actualChildNodes = actual.ChildNodes().ToArray(); - - int expectedCount = expectedChildNodes.Length; - int actualCount = actualChildNodes.Length; - if (expectedCount != actualCount) - { - Debug.Assert(false, $"Child nodes mismatch. Expected= {expected}, Actual= {actual}"); - return; - } - for (int ch = 0; ch < expectedCount; ch++) - { - FindTreeDiff(expectedChildNodes[ch], actualChildNodes[ch]); - } - return; - } - } } } From 79b009f220a58ad7ebf081cdca0d49edf61244c7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 5 Aug 2021 23:51:14 -0700 Subject: [PATCH 035/149] More Trimmers --- TestMethod.cs | 13 +- .../Expressions/AssignExprRemoval.cs | 37 +++ .../Rewriters/Expressions/CastExprRemoval.cs | 11 +- .../Rewriters/Expressions/FieldExprRemoval.cs | 37 +++ .../Expressions/InvocationExprRemoval.cs | 28 ++ .../Statements/ConsoleLogStmtRemoval.cs | 35 +++ ...ssignStmtRemoval.cs => ExprStmtRemoval.cs} | 2 +- .../Statements/StructDeclStmtRemoval.cs | 29 ++ .../Rewriters/Statements/SwitchStmtRemoval.cs | 29 ++ .../Statements/TryCatchFinallyStmtRemoval.cs | 29 ++ Trimmer/TestTrimmer.cs | 252 ++++++++++++++---- 11 files changed, 440 insertions(+), 62 deletions(-) create mode 100644 Trimmer/Rewriters/Expressions/AssignExprRemoval.cs create mode 100644 Trimmer/Rewriters/Expressions/FieldExprRemoval.cs create mode 100644 Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs rename Trimmer/Rewriters/Statements/{AssignStmtRemoval.cs => ExprStmtRemoval.cs} (95%) create mode 100644 Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs create mode 100644 Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs diff --git a/TestMethod.cs b/TestMethod.cs index 83b4463..bc5b49a 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -627,6 +627,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) ExprKind switchExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(switchType); ExpressionSyntax switchExpr = ExprHelper(switchExprKind, switchExprType, 0); IList listOfCases = new List(); + HashSet usedCaseLabels = new HashSet(); // Generate each cases for (int i = 0; i < caseCount; i++) @@ -655,11 +656,15 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) caseBody.Add(BreakStatement()); PopScope(); // pop 'case' body scope + + LiteralExpressionSyntax caseLiteralExpression; + do + { + caseLiteralExpression = ExprHelper(ExprKind.LiteralExpression, switchExprType, 0) as LiteralExpressionSyntax; + } while (!usedCaseLabels.Add(caseLiteralExpression.Token.ValueText)); + listOfCases.Add(SwitchSection() - .WithLabels( - SingletonList( - CaseSwitchLabel( - ExprHelper(ExprKind.LiteralExpression, switchExprType, 0)))) + .WithLabels(SingletonList(CaseSwitchLabel(caseLiteralExpression))) .WithStatements(caseBody.ToSyntaxList())); } diff --git a/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs b/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs new file mode 100644 index 0000000..f832b64 --- /dev/null +++ b/Trimmer/Rewriters/Expressions/AssignExprRemoval.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class AssignExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node) + { + string assignmentExpr = node.ToFullString(); + if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) + { + return base.VisitAssignmentExpression(node); + } + + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + + return null; + } + + return base.VisitAssignmentExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs index fb281b3..7d0a7bd 100644 --- a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs @@ -20,8 +20,15 @@ public override SyntaxNode VisitCastExpression(CastExpressionSyntax node) { isAnyNodeVisited = true; - var expr = (ParenthesizedExpressionSyntax)node.ChildNodes().ToList()[1]; - return VisitParenthesizedExpression(expr); + var expr = node.ChildNodes().ToList()[1]; + if (expr is ParenthesizedExpressionSyntax parenExpr) + { + return VisitParenthesizedExpression(parenExpr); + } + else if (expr is LiteralExpressionSyntax literalExpr) + { + return VisitLiteralExpression(literalExpr); + } } return base.VisitCastExpression(node); diff --git a/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs b/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs new file mode 100644 index 0000000..8749eee --- /dev/null +++ b/Trimmer/Rewriters/Expressions/FieldExprRemoval.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class FieldExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node) + { + string assignmentExpr = node.ToFullString(); + if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || + assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) + { + return base.VisitFieldDeclaration(node); + } + + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + + return null; + } + + return base.VisitFieldDeclaration(node); + } + } +} diff --git a/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs b/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs new file mode 100644 index 0000000..4b91276 --- /dev/null +++ b/Trimmer/Rewriters/Expressions/InvocationExprRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters.Statements +{ + public class InvocationExprRemoval : SyntaxRewriter + { + public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + { + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + return null; + } + + return base.VisitInvocationExpression(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs new file mode 100644 index 0000000..8764d40 --- /dev/null +++ b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Antigen.Trimmer.Rewriters.Statements +{ + /// + /// Only removes all Console.Log at once. + /// + public class ConsoleLogStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) + { + if (removeAll) + { + if (node.ToFullString().Trim().StartsWith("Console.WriteLine")) + { + isAnyNodeVisited = true; + return null; + } + } + + return base.VisitExpressionStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs similarity index 95% rename from Trimmer/Rewriters/Statements/AssignStmtRemoval.cs rename to Trimmer/Rewriters/Statements/ExprStmtRemoval.cs index cb82d56..99b66ce 100644 --- a/Trimmer/Rewriters/Statements/AssignStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs @@ -12,7 +12,7 @@ namespace Antigen.Trimmer.Rewriters { - public class AssignStmtRemoval : SyntaxRewriter + public class ExprStmtRemoval : SyntaxRewriter { public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) { diff --git a/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs new file mode 100644 index 0000000..050c4c1 --- /dev/null +++ b/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class StructDeclStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) + { + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + + return null; + } + + return base.VisitStructDeclaration(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs b/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs new file mode 100644 index 0000000..e15f39a --- /dev/null +++ b/Trimmer/Rewriters/Statements/SwitchStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class SwitchStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitSwitchStatement(SwitchStatementSyntax node) + { + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + + return null; + } + + return base.VisitSwitchStatement(node); + } + } +} diff --git a/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs b/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs new file mode 100644 index 0000000..24684f0 --- /dev/null +++ b/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Antigen.Trimmer.Rewriters +{ + public class TryCatchFinallyStmtRemoval : SyntaxRewriter + { + public override SyntaxNode VisitTryStatement(TryStatementSyntax node) + { + if (currId++ == id || removeAll) + { + isAnyNodeVisited = true; + + return null; + } + + return base.VisitTryStatement(node); + } + } +} diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 6e69f52..13762a5 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -20,16 +21,60 @@ namespace Antigen.Trimmer { public class TestTrimmer { - RunOptions RunOptions; + RunOptions _runOptions; private string _testFileToTrim; private static TestRunner _testRunner; + private Dictionary _baselineVariables; + private Dictionary _testVariables; + private string _originalTestAssertion; static int s_iterId = 1; + private static readonly Regex s_jitAssertionRegEx = new Regex("Assertion failed '(.*)' in '(.*)' during '(.*)'"); + private static readonly Regex s_coreclrAssertionRegEx = new Regex(@"Assert failure\(PID \d+ \[0x[0-9a-f]+], Thread: \d+ \[0x[0-9a-f]+]\):(.*)"); + public TestTrimmer(string testFileToTrim, RunOptions runOptions) { - RunOptions = runOptions; + if (!File.Exists(testFileToTrim)) + { + throw new Exception($"{testFileToTrim} doesn't exist."); + } + _runOptions = runOptions; _testFileToTrim = testFileToTrim; - _testRunner = TestRunner.GetInstance(RunOptions); + _testRunner = TestRunner.GetInstance(_runOptions); + + ParseEnvironment(); + } + + /// + /// Returns a tuple of Baseline, Test environment variables + /// + /// + private void ParseEnvironment() + { + var fileContents = File.ReadAllText(_testFileToTrim); + string[] fileContentLines = fileContents.Split(Environment.NewLine); + _originalTestAssertion = ParseAssertionError(fileContents); + + foreach (var line in fileContentLines) + { + if (line.StartsWith("// BaselineVars: ")) + { + var baselineContents = line.Replace("// BaselineVars: ", string.Empty); + _baselineVariables = baselineContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); + continue; + } + + else if (line.StartsWith("// TestVars: ")) + { + var testContents = line.Replace("// TestVars: ", string.Empty); + _testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); + return; + } + + throw new Exception("Baseline/TestVars not present."); + } + //throw new Exception("Baseline/TestVars not present."); + //return null; } public void Trim() @@ -45,11 +90,13 @@ public void Trim() /// public void TrimTree() { - bool trimmedAtleastOne = false; + bool trimmedAtleastOne; do { + trimmedAtleastOne = false; trimmedAtleastOne |= TrimStatements(); trimmedAtleastOne |= TrimExpressions(); + trimmedAtleastOne |= TrimEnvVars(); } while (trimmedAtleastOne); @@ -69,13 +116,16 @@ public bool TrimStatements() // statements/blocks new MethodDeclStmtRemoval(), + new ConsoleLogStmtRemoval(), new StructDeclStmtRemoval(), new BlockRemoval(), new DoWhileStmtRemoval(), new ForStmtRemoval(), new WhileStmtRemoval(), + new TryCatchFinallyStmtRemoval(), + new SwitchStmtRemoval(), new IfElseStmtRemoval(), - new AssignStmtRemoval(), + new ExprStmtRemoval(), new LocalDeclStmtRemoval(), }; @@ -85,7 +135,7 @@ public bool TrimStatements() do { trimmedInCurrIter = false; - trimmedInCurrIter |= TrimWithTrimmer(trimmerList); + trimmedInCurrIter |= Trim(trimmerList); trimmedAtleastOne |= trimmedInCurrIter; } while (trimmedInCurrIter); @@ -105,12 +155,15 @@ public bool TrimExpressions() // From high to low // expressions + new InvocationExprRemoval(), + new FieldExprRemoval(), new CastExprRemoval(), new ParenExprRemoval(), new BinaryExpRemoval(), - //new MemberAccessExprRemoval(), - //new LiteralExprRemoval(), - //new IdentityNameExprRemoval(), + new AssignExprRemoval(), + new MemberAccessExprRemoval(), + new LiteralExprRemoval(), + new IdentityNameExprRemoval(), }; bool trimmedAtleastOne = false; @@ -119,19 +172,49 @@ public bool TrimExpressions() do { trimmedInCurrIter = false; - trimmedInCurrIter |= TrimWithTrimmer(trimmerList); + trimmedInCurrIter |= Trim(trimmerList); trimmedAtleastOne |= trimmedInCurrIter; } while (trimmedInCurrIter); return trimmedAtleastOne; } + public bool TrimEnvVars() + { + bool trimmedAtleastOne = false; + SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + var keys = _testVariables.Keys.ToList(); + + foreach(var envVar in keys) + { + string value = _testVariables[envVar]; + + _testVariables.Remove(envVar); + if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) == TestResult.Pass) + { + _testVariables[envVar] = value; + } + else + { + trimmedAtleastOne = true; + } + } + + return trimmedAtleastOne; + } + /// /// Trim the test case. /// - private bool TrimWithTrimmer(List trimmerList) + private bool Trim(List trimmerList) { SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + CompileResult compileResult = _testRunner.Compile(recentTree.SyntaxTree, "base"); + if (compileResult.AssemblyName == null) + { + return false; + } + bool trimmedAtleastOne = false; bool trimmedInCurrIter; @@ -139,46 +222,52 @@ private bool TrimWithTrimmer(List trimmerList) { trimmedInCurrIter = false; - //TODO: populate baseline and test envvars: - Dictionary baselineEnvVars = Rsln.BaselineEnvVars; - Dictionary testEnvVars = new Dictionary() - { - {"COMPlus_JitStress", "2" }, - {"COMPlus_JitStressRegs", "0x80" }, - {"COMPlus_TieredCompilation", "0" } - }; - TestResult reproTestResult = TestResult.Fail; - // pick category foreach (var trimmer in trimmerList) { - SyntaxNode treeBeforeTrim = recentTree, treeAfterTrim; + SyntaxNode treeBeforeTrim = recentTree, treeAfterTrim = null; // remove all Console.Write($"{s_iterId}. {trimmer.GetType()}"); - int noOfNodes; - - // For expression, it can be nested, so first count - // total expressions present. - if (trimmer is BinaryExpRemoval) + int noOfNodes = 0; + bool gotException = false; + try { - treeAfterTrim = trimmer.Visit(recentTree); - noOfNodes = trimmer.TotalVisited; - trimmer.RemoveAll(); - treeAfterTrim = trimmer.Visit(recentTree); + // For expression, it can be nested, so first count + // total expressions present. + if (trimmer is BinaryExpRemoval) + { + treeAfterTrim = trimmer.Visit(recentTree); + noOfNodes = trimmer.TotalVisited; + trimmer.RemoveAll(); + treeAfterTrim = trimmer.Visit(recentTree); + } + // for statements, count while removing them all. + else + { + trimmer.RemoveAll(); + treeAfterTrim = trimmer.Visit(recentTree); + noOfNodes = trimmer.TotalVisited; + } } - // for statements, count while removing them all. - else + catch (ArgumentNullException ae) { - trimmer.RemoveAll(); + gotException = true; + } - treeAfterTrim = trimmer.Visit(recentTree); - noOfNodes = trimmer.TotalVisited; + bool isSameTree = false; + if (!gotException) + { + treeAfterTrim = RslnUtilities.GetValidSyntaxTree(treeAfterTrim, doValidation: false).GetRoot(); + isSameTree = treeBeforeTrim.ToFullString() == treeAfterTrim.ToFullString(); } // compile, execute and repro - if (trimmer.IsAnyNodeVisited && Verify($"trim{s_iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + if (!gotException && + !isSameTree && // If they are same tree + trimmer.IsAnyNodeVisited && // We have visited and removed at least one node + Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == TestResult.Fail) { // move to next trimmer recentTree = treeAfterTrim; @@ -192,7 +281,6 @@ private bool TrimWithTrimmer(List trimmerList) Console.WriteLine(" - Revert"); } - trimmer.Reset(); trimmer.RemoveOneByOne(); @@ -207,8 +295,18 @@ private bool TrimWithTrimmer(List trimmerList) treeBeforeTrim = recentTree; treeAfterTrim = trimmer.Visit(recentTree); + isSameTree = false; + if (!gotException) + { + treeAfterTrim = RslnUtilities.GetValidSyntaxTree(treeAfterTrim, doValidation: false).GetRoot(); + isSameTree = treeBeforeTrim.ToFullString() == treeAfterTrim.ToFullString(); + } + // compile, execute and repro - if (trimmer.IsAnyNodeVisited && Verify($"trim{s_iterId++}", treeAfterTrim, baselineEnvVars, testEnvVars) == reproTestResult) + if (!gotException && + !isSameTree && + trimmer.IsAnyNodeVisited && + Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == TestResult.Fail) { // move to next trimmer recentTree = treeAfterTrim; @@ -252,7 +350,7 @@ private bool TrimWithTrimmer(List trimmerList) //TODO: refactor and merge with TestCase's Verify private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary baselineEnvVars, Dictionary testEnvVars/*, bool skipBaseline*/) { - StringBuilder fileContents = new StringBuilder(); + bool hasAssertion = !string.IsNullOrEmpty(_originalTestAssertion); CompileResult compileResult = _testRunner.Compile(programRootNode.SyntaxTree, iterId); if (compileResult.AssemblyFullPath == null) { @@ -264,32 +362,53 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); //} - string baseline = _testRunner.Execute(compileResult, Rsln.BaselineEnvVars); - string test = _testRunner.Execute(compileResult, testEnvVars); + string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, Switches.BaseLineVars()); + string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars); - if (baseline == test) + TestResult verificationResult = TestResult.Fail; + + if (currRunBaselineOutput == currRunTestOutput) { - try + // If output matches, then the test passes + verificationResult = TestResult.Pass; + } + else if (hasAssertion) + { + // Otherwise, if there was an assertion, verify that it is the same assertion + var currRunTestAssertion = ParseAssertionError(currRunTestOutput); + if (_originalTestAssertion != currRunTestAssertion) { - File.Delete(compileResult.AssemblyFullPath); + // The assertion doesn't match. Consider this as PASS + verificationResult = TestResult.Pass; } - catch (Exception) + } + + foreach (string knownError in knownDiffs) + { + if (currRunBaselineOutput.Contains(knownError) && currRunTestOutput.Contains(knownError)) { - // ignore errors + verificationResult = TestResult.Pass; + break; } - return TestResult.Pass; } - foreach (string knownError in knownDiffs) + if (verificationResult == TestResult.Pass) { - if (baseline.Contains(knownError) && test.Contains(knownError)) + try { - return TestResult.Pass; + File.Delete(compileResult.AssemblyFullPath); } + catch (Exception) + { + // ignore errors + } + return TestResult.Pass; } string programContents = programRootNode.ToFullString(); programContents = Regex.Replace(programContents, @"[\r\n]*$", string.Empty, RegexOptions.Multiline); + + StringBuilder fileContents = new StringBuilder(); fileContents.AppendLine(programContents); fileContents.AppendLine("/*"); fileContents.AppendLine($"Got output diff:"); @@ -303,7 +422,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); } fileContents.AppendLine(); - fileContents.AppendLine(baseline); + fileContents.AppendLine(currRunBaselineOutput); fileContents.AppendLine("--------- Test --------- "); fileContents.AppendLine(); @@ -314,18 +433,41 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); } fileContents.AppendLine(); - fileContents.AppendLine(test); + fileContents.AppendLine(currRunTestOutput); fileContents.AppendLine("*/"); //TODO: Only if something was visited string failedFileName = $"{iterId}-lkg"; - string failFile = Path.Combine(@"E:\temp\antigen-trimmer\test2\round9", $"{ failedFileName}.g.cs"); + string failFile = Path.Combine(Path.GetDirectoryName(_testFileToTrim), $"{ failedFileName}.g.cs"); //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); + _testFileToTrim = failFile; - File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); + File.Move(compileResult.AssemblyFullPath, Path.Combine(_runOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); return TestResult.Fail; } + + /// + /// Parse assertion errors in output + /// + /// + /// + private static string ParseAssertionError(string output) + { + Match assertionMatch; + assertionMatch = s_jitAssertionRegEx.Match(output); + if (assertionMatch.Success) + { + return assertionMatch.Value; + } + + assertionMatch = s_coreclrAssertionRegEx.Match(output); + if (assertionMatch.Success) + { + return assertionMatch.Value; + } + return null; + } } } From 8ed346cc2c79774606882e1055e501acb87c3dcc Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:01:36 -0700 Subject: [PATCH 036/149] Bug fixes and improvements in Trimmer --- Helpers/RslnUtilities.cs | 39 +++++++++++ .../Expressions/AssignExprRemoval.cs | 8 --- .../Rewriters/Expressions/FieldExprRemoval.cs | 6 -- Trimmer/Rewriters/Statements/BlockRemoval.cs | 2 +- .../Rewriters/Statements/ExprStmtRemoval.cs | 6 -- .../Rewriters/Statements/IfElseStmtRemoval.cs | 1 + .../Statements/LocalDeclStmtRemoval.cs | 9 --- Trimmer/TestTrimmer.cs | 67 ++++++++----------- 8 files changed, 69 insertions(+), 69 deletions(-) diff --git a/Helpers/RslnUtilities.cs b/Helpers/RslnUtilities.cs index 5035875..14f5450 100644 --- a/Helpers/RslnUtilities.cs +++ b/Helpers/RslnUtilities.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -16,6 +17,9 @@ namespace Antigen { public class RslnUtilities { + private static readonly Regex s_jitAssertionRegEx = new Regex("Assertion failed '(.*)' in '(.*)' during '(.*)'"); + private static readonly Regex s_coreclrAssertionRegEx = new Regex(@"Assert failure\(PID \d+ \[0x[0-9a-f]+], Thread: \d+ \[0x[0-9a-f]+]\):(.*)"); + public static SyntaxTree GetValidSyntaxTree(SyntaxNode treeRoot, bool doValidation = true) { @@ -67,5 +71,40 @@ private static void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) return; } } + + /// + /// Parse assertion errors in output + /// + /// + /// + internal static string ParseAssertionError(string output) + { + if (string.IsNullOrEmpty(output)) + { + return null; + } + + // If Fatal error, return text as it is. + if (output.Contains("Fatal error.")) + { + return output; + } + + + // Otherwise, try to match for JIT asserts + Match assertionMatch; + assertionMatch = s_jitAssertionRegEx.Match(output); + if (assertionMatch.Success) + { + return assertionMatch.Value; + } + + assertionMatch = s_coreclrAssertionRegEx.Match(output); + if (assertionMatch.Success) + { + return assertionMatch.Value; + } + return null; + } } } diff --git a/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs b/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs index f832b64..becec74 100644 --- a/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs @@ -16,14 +16,6 @@ public class AssignExprRemoval : SyntaxRewriter { public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node) { - string assignmentExpr = node.ToFullString(); - if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) - { - return base.VisitAssignmentExpression(node); - } - if (currId++ == id || removeAll) { isAnyNodeVisited = true; diff --git a/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs b/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs index 8749eee..e2496ce 100644 --- a/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs @@ -17,12 +17,6 @@ public class FieldExprRemoval : SyntaxRewriter public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node) { string assignmentExpr = node.ToFullString(); - if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) - { - return base.VisitFieldDeclaration(node); - } if (currId++ == id || removeAll) { diff --git a/Trimmer/Rewriters/Statements/BlockRemoval.cs b/Trimmer/Rewriters/Statements/BlockRemoval.cs index 24d34be..465742d 100644 --- a/Trimmer/Rewriters/Statements/BlockRemoval.cs +++ b/Trimmer/Rewriters/Statements/BlockRemoval.cs @@ -19,7 +19,7 @@ public override SyntaxNode VisitBlock(BlockSyntax node) { if (node.Statements.Count == 0) { - return node; + return null; } if (currId++ == id || removeAll) diff --git a/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs index 99b66ce..650ff3b 100644 --- a/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs @@ -17,12 +17,6 @@ public class ExprStmtRemoval : SyntaxRewriter public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) { string assignmentExpr = node.ToFullString(); - if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) - { - return base.VisitExpressionStatement(node); - } if (currId++ == id || removeAll) { diff --git a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs index 320d21e..c5ceee6 100644 --- a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs @@ -24,6 +24,7 @@ public override SyntaxNode VisitIfStatement(IfStatementSyntax node) if (currId++ == id || removeAll) { isAnyNodeVisited = true; + //TODO: Also - return node.WithElse(null); return null; } diff --git a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs index 2901388..9208184 100644 --- a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs @@ -16,15 +16,6 @@ public class LocalDeclStmtRemoval : SyntaxRewriter { public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { - string assignmentExpr = node.ToFullString(); - if (assignmentExpr.Contains("loopvar", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopInvariant", StringComparison.InvariantCultureIgnoreCase) || - assignmentExpr.Contains("loopSecondaryVar", StringComparison.InvariantCultureIgnoreCase)) - { - return base.VisitLocalDeclarationStatement(node); - } - - if (currId++ == id || removeAll) { isAnyNodeVisited = true; diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 13762a5..826ec56 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -29,9 +29,6 @@ public class TestTrimmer private string _originalTestAssertion; static int s_iterId = 1; - private static readonly Regex s_jitAssertionRegEx = new Regex("Assertion failed '(.*)' in '(.*)' during '(.*)'"); - private static readonly Regex s_coreclrAssertionRegEx = new Regex(@"Assert failure\(PID \d+ \[0x[0-9a-f]+], Thread: \d+ \[0x[0-9a-f]+]\):(.*)"); - public TestTrimmer(string testFileToTrim, RunOptions runOptions) { if (!File.Exists(testFileToTrim)) @@ -53,7 +50,7 @@ private void ParseEnvironment() { var fileContents = File.ReadAllText(_testFileToTrim); string[] fileContentLines = fileContents.Split(Environment.NewLine); - _originalTestAssertion = ParseAssertionError(fileContents); + _originalTestAssertion = RslnUtilities.ParseAssertionError(fileContents); foreach (var line in fileContentLines) { @@ -157,13 +154,14 @@ public bool TrimExpressions() // expressions new InvocationExprRemoval(), new FieldExprRemoval(), - new CastExprRemoval(), - new ParenExprRemoval(), new BinaryExpRemoval(), new AssignExprRemoval(), new MemberAccessExprRemoval(), new LiteralExprRemoval(), new IdentityNameExprRemoval(), + new CastExprRemoval(), + new ParenExprRemoval(), + }; bool trimmedAtleastOne = false; @@ -217,6 +215,7 @@ private bool Trim(List trimmerList) bool trimmedAtleastOne = false; bool trimmedInCurrIter; + TestResult expectedResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; do { @@ -251,7 +250,7 @@ private bool Trim(List trimmerList) noOfNodes = trimmer.TotalVisited; } } - catch (ArgumentNullException ae) + catch (ArgumentNullException) { gotException = true; } @@ -267,7 +266,7 @@ private bool Trim(List trimmerList) if (!gotException && !isSameTree && // If they are same tree trimmer.IsAnyNodeVisited && // We have visited and removed at least one node - Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == TestResult.Fail) + Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == expectedResult) { // move to next trimmer recentTree = treeAfterTrim; @@ -293,7 +292,15 @@ private bool Trim(List trimmerList) trimmer.UpdateId(nodeId); treeBeforeTrim = recentTree; - treeAfterTrim = trimmer.Visit(recentTree); + treeAfterTrim = null; + + try + { + treeAfterTrim = trimmer.Visit(recentTree); + } catch (ArgumentNullException) + { + gotException = true; + } isSameTree = false; if (!gotException) @@ -306,7 +313,7 @@ private bool Trim(List trimmerList) if (!gotException && !isSameTree && trimmer.IsAnyNodeVisited && - Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == TestResult.Fail) + Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == expectedResult) { // move to next trimmer recentTree = treeAfterTrim; @@ -365,9 +372,10 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, Switches.BaseLineVars()); string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars); - TestResult verificationResult = TestResult.Fail; + TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; - if (currRunBaselineOutput == currRunTestOutput) + if (((currRunBaselineOutput == "TIMEOUT") && (currRunTestOutput == "TIMEOUT")) || + (currRunBaselineOutput == currRunTestOutput)) { // If output matches, then the test passes verificationResult = TestResult.Pass; @@ -375,7 +383,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< else if (hasAssertion) { // Otherwise, if there was an assertion, verify that it is the same assertion - var currRunTestAssertion = ParseAssertionError(currRunTestOutput); + var currRunTestAssertion = RslnUtilities.ParseAssertionError(currRunTestOutput); if (_originalTestAssertion != currRunTestAssertion) { // The assertion doesn't match. Consider this as PASS @@ -417,9 +425,12 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine(); fileContents.AppendLine("Environment:"); fileContents.AppendLine(); - foreach (var envVars in baselineEnvVars) + if (baselineEnvVars != null) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + foreach (var envVars in baselineEnvVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } } fileContents.AppendLine(); fileContents.AppendLine(currRunBaselineOutput); @@ -445,29 +456,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< _testFileToTrim = failFile; File.Move(compileResult.AssemblyFullPath, Path.Combine(_runOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); - return TestResult.Fail; - } - - /// - /// Parse assertion errors in output - /// - /// - /// - private static string ParseAssertionError(string output) - { - Match assertionMatch; - assertionMatch = s_jitAssertionRegEx.Match(output); - if (assertionMatch.Success) - { - return assertionMatch.Value; - } - - assertionMatch = s_coreclrAssertionRegEx.Match(output); - if (assertionMatch.Success) - { - return assertionMatch.Value; - } - return null; - } + return verificationResult; + } } } From 4a4bc2ae14f5dabbe63374164bab2853f2edf8fd Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:04:02 -0700 Subject: [PATCH 037/149] (Almost) fix DivideByZero known errors --- TestMethod.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TestMethod.cs b/TestMethod.cs index bc5b49a..1227da7 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -390,7 +390,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); } @@ -770,7 +770,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i // For division, make sure that divisor is not 0 if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, exprType, rhs); } @@ -806,7 +806,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(100))))); + rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); } From 9da9074e313ee3b19f43f807580aea66a59e124b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:04:50 -0700 Subject: [PATCH 038/149] Have lower values of literals --- Helpers/Literals.cs | 190 +++++++++++++++++++++++++++----------------- 1 file changed, 117 insertions(+), 73 deletions(-) diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index 7eba775..79f5b1e 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -16,6 +16,23 @@ public static partial class Helpers { private static char[] Alphabet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + private static IList> Numerals = new List>() + { + new Weights(int.MinValue, (double) PRNG.Next(1, 10) / 10000 ), + new Weights(int.MinValue + 1, (double)PRNG.Next(1, 10) / 10000 ), + new Weights(PRNG.Next(-100, -6), (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-5, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-2, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-1, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(0, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(1, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(2, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(5, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(PRNG.Next(6, 100), (double) PRNG.Next(1, 10) / 1000 ), + new Weights(int.MaxValue - 1, (double) PRNG.Next(1, 10) / 10000 ), + new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), + }; + public static byte GetRandomByte() { return (byte)PRNG.Next(byte.MinValue, byte.MaxValue); @@ -79,96 +96,123 @@ public static sbyte GetRandomSByte() public static float GetRandomFloat() { - return (float)(PRNG.Next(int.MaxValue) + 1.5); + return (float)PRNG.Next(10) + (1 / PRNG.Next(1, 5)); } public static double GetRandomDouble() { - return (double)(PRNG.Next(int.MaxValue) + 2.5); + return (double)PRNG.Next(10) + (1 / PRNG.Next(1, 5)); } public static decimal GetRandomDecimal() { - return (decimal)(PRNG.Next(int.MaxValue) + 3.5); + return (decimal)PRNG.Next(10) + (1 / PRNG.Next(1, 5)); } public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType literalType) { SyntaxToken literalToken; SyntaxKind kind; - switch (literalType.PrimitiveType) + + if ((literalType.PrimitiveType & Primitive.Numeric) != 0) { - case Tree.Primitive.Boolean: - if (GetRandomBoolean()) - { - kind = SyntaxKind.TrueLiteralExpression; - literalToken = Token(SyntaxKind.TrueKeyword); - } - else + // numeric + kind = SyntaxKind.NumericLiteralExpression; + int literalValue = PRNG.WeightedChoice(Numerals); + + // If unsigned, and number selected is negative, then flip it + if ((literalType.PrimitiveType & Primitive.UnsignedInteger) != 0) + { + if (literalValue < 0) { - kind = SyntaxKind.FalseLiteralExpression; - literalToken = Token(SyntaxKind.FalseKeyword); + if (literalValue == int.MinValue) + { + literalValue = int.MaxValue; + } + else + { + literalValue *= -1; + } } - break; - case Tree.Primitive.Byte: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomByte()); - break; - case Tree.Primitive.Char: - kind = SyntaxKind.CharacterLiteralExpression; - literalToken = Literal(GetRandomChar()); - break; - case Tree.Primitive.Short: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomShort()); - break; - case Tree.Primitive.Int: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomInt()); - break; - case Tree.Primitive.Long: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomLong()); - break; - case Tree.Primitive.UShort: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomUShort()); - break; - case Tree.Primitive.UInt: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomUInt()); - break; - case Tree.Primitive.ULong: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomULong()); - break; - case Tree.Primitive.SByte: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomSByte()); - break; - case Tree.Primitive.Float: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomFloat()); - break; - case Tree.Primitive.Decimal: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomDecimal()); - break; - case Tree.Primitive.Double: - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(GetRandomDouble()); - break; - case Tree.Primitive.String: - kind = SyntaxKind.StringLiteralExpression; - literalToken = Literal(GetRandomString()); - break; - default: - Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); - - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(1); - break; - + } + + switch (literalType.PrimitiveType) + { + case Tree.Primitive.Byte: + literalToken = Literal((byte)(literalValue % byte.MaxValue)); + break; + case Tree.Primitive.SByte: + literalToken = Literal((sbyte)(literalValue % sbyte.MaxValue)); + break; + case Tree.Primitive.UShort: + literalToken = Literal((ushort)(literalValue % ushort.MaxValue)); + break; + case Tree.Primitive.Short: + literalToken = Literal((short)(literalValue % short.MaxValue)); + break; + case Tree.Primitive.Int: + literalToken = Literal(literalValue); + break; + case Tree.Primitive.UInt: + literalToken = Literal(literalValue); + break; + case Tree.Primitive.Long: + literalToken = Literal(literalValue); + break; + case Tree.Primitive.ULong: + literalToken = Literal(literalValue); + break; + case Tree.Primitive.Float: + literalToken = Literal((float)literalValue + (float)PRNG.Next(5) / PRNG.Next(10, 100)); + break; + case Tree.Primitive.Decimal: + literalToken = Literal((decimal)literalValue + (decimal)PRNG.Next(5) / PRNG.Next(10, 100)); + break; + case Tree.Primitive.Double: + literalToken = Literal((double)literalValue + (double)PRNG.Next(5) / PRNG.Next(10, 100)); + break; + default: + Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); + + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(1); + break; + } + } + else + { + // non-numeric + switch (literalType.PrimitiveType) + { + case Tree.Primitive.Boolean: + if (GetRandomBoolean()) + { + kind = SyntaxKind.TrueLiteralExpression; + literalToken = Token(SyntaxKind.TrueKeyword); + } + else + { + kind = SyntaxKind.FalseLiteralExpression; + literalToken = Token(SyntaxKind.FalseKeyword); + } + break; + + case Tree.Primitive.Char: + kind = SyntaxKind.CharacterLiteralExpression; + literalToken = Literal(GetRandomChar()); + break; + + case Tree.Primitive.String: + kind = SyntaxKind.StringLiteralExpression; + literalToken = Literal(GetRandomString()); + break; + default: + Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); + + kind = SyntaxKind.NumericLiteralExpression; + literalToken = Literal(1); + break; + } } return LiteralExpression(kind, literalToken); From 149f04eb3dcd863d9214e8201156e4e0679b13a6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:05:59 -0700 Subject: [PATCH 039/149] Adjust tests configuration --- Config/ConfigOptions.cs | 104 ++++++++++++++++++++-------------------- TestClass.cs | 2 +- TestMethod.cs | 4 +- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index f21e6ce..5d255e6 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -24,30 +24,30 @@ public class ConfigOptions : OptionsBase public double AssignWeight = 0.4; // Statement weights - public double VariableDeclarationWeight = 0.3; - public double IfElseStatementWeight = 0.4; - public double AssignStatementWeight = 0.5; - public double ForStatementWeight = 0.4; + public double VariableDeclarationWeight = 0.03; //TODO: Reduce this and add aliases when we see this. + public double IfElseStatementWeight = 0.2; + public double AssignStatementWeight = 0.6; + public double ForStatementWeight = 0.3; public double DoWhileStatementWeight = 0.2; public double WhileStatementWeight = 0.3; public double TryCatchFinallyStatementWeight = 0.4; public double SwitchStatementWeight = 0.1; // Type weights - public double BooleanWeight = 1; - public double ByteWeight = 1; - public double CharWeight = 1; - public double DecimalWeight = 1; - public double DoubleWeight = 1; - public double Int16Weight = 1; - public double Int32Weight = 1; - public double Int64Weight = 1; - public double SByteWeight = 1; - public double SingleWeight = 1; - public double StringWeight = 1; - public double UInt16Weight = 1; - public double UInt32Weight = 1; - public double UInt64Weight = 1; + public double BooleanWeight = 0.3; + public double ByteWeight = 0.4; + public double CharWeight = 0.03; + public double DecimalWeight = 0.5; + public double DoubleWeight = 0.4; + public double Int16Weight = 0.4; + public double Int32Weight = 0.45; + public double Int64Weight = 0.48; + public double SByteWeight = 0.3; + public double SingleWeight = 0.6; + public double StringWeight = 0.03; + public double UInt16Weight = 0.4; + public double UInt32Weight = 0.45; + public double UInt64Weight = 0.6; // Operator weights public double UnaryPlusWeight = 1; @@ -60,40 +60,40 @@ public class ConfigOptions : OptionsBase public double BitwiseNotWeight = 1; public double TypeOfWeight = 1; - public double AddWeight = 1; - public double SubtractWeight = 1; - public double MultiplyWeight = 1; - public double DivideWeight = 1; - public double ModuloWeight = 1; - public double LeftShiftWeight = 1; - public double RightShiftWeight = 1; - - public double SimpleAssignmentWeight = 1; - public double AddAssignmentWeight = 1; - public double SubtractAssignmentWeight = 1; - public double MultiplyAssignmentWeight = 1; - public double DivideAssignmentWeight = 1; - public double ModuloAssignmentWeight = 1; - public double LeftShiftAssignmentWeight = 1; - public double RightShiftAssignmentWeight = 1; - - public double LogicalAndWeight = 1; - public double LogicalOrWeight = 1; - - public double BitwiseAndWeight = 1; - public double BitwiseOrWeight = 1; - public double ExclusiveOrWeight = 1; - - public double AndAssignmentWeight = 1; - public double OrAssignmentWeight = 1; - public double ExclusiveOrAssignmentWeight = 1; - - public double LessThanWeight = 1; - public double LessThanOrEqualWeight = 1; - public double GreaterThanWeight = 1; - public double GreaterThanOrEqualWeight = 1; - public double EqualsWeight = 1; - public double NotEqualsWeight = 1; + public double AddWeight = 0.9; + public double SubtractWeight = 0.5; + public double MultiplyWeight = 0.5; + public double DivideWeight = 0.4; + public double ModuloWeight = 0.5; + public double LeftShiftWeight = 0.6; + public double RightShiftWeight = 0.4; + + public double SimpleAssignmentWeight = 0.9; + public double AddAssignmentWeight = 0.5; + public double SubtractAssignmentWeight = 0.6; + public double MultiplyAssignmentWeight = 0.5; + public double DivideAssignmentWeight = 0.5; + public double ModuloAssignmentWeight = 0.3; + public double LeftShiftAssignmentWeight = 0.5; + public double RightShiftAssignmentWeight = 0.6; + + public double LogicalAndWeight = 0.5; + public double LogicalOrWeight = 0.4; + + public double BitwiseAndWeight = 0.45; + public double BitwiseOrWeight = 0.35; + public double ExclusiveOrWeight = 0.45; + + public double AndAssignmentWeight = 0.54; + public double OrAssignmentWeight = 0.59; + public double ExclusiveOrAssignmentWeight = 0.68; + + public double LessThanWeight = 0.6; + public double LessThanOrEqualWeight = 0.6; + public double GreaterThanWeight = 0.51; + public double GreaterThanOrEqualWeight = 0.51; + public double EqualsWeight = 0.8; + public double NotEqualsWeight = 0.8; // Config options // Probablity of removing loop parameters -- see comments on BoundParameters in ForStatement diff --git a/TestClass.cs b/TestClass.cs index 0c42fec..ef63eca 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -183,7 +183,7 @@ private IList GenerateMethods() List methods = new List(); //TODO-config: No. of methods per class - for (int i = 1; i < 5; i++) + for (int i = 1; i < 2; i++) { var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); diff --git a/TestMethod.cs b/TestMethod.cs index 1227da7..7d57949 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -23,7 +23,7 @@ public class TestMethod protected readonly int _stmtCount; //TODO-config: Move this to ConfigOptions - private static readonly int s_maxStatements = 4; + private static readonly int s_maxStatements = 8; #if DEBUG private Dictionary expressionsCount = new Dictionary(); @@ -745,7 +745,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i ExprKind lhsExprKind, rhsExprKind; //TODO-config: Add MaxDepth in config - if (depth >= 5) + if (depth >= 3) { lhsExprKind = rhsExprKind = ExprKind.LiteralExpression; } From e5dedfc06e918857ca25aec9ce6f8e5d60e89ea8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:06:27 -0700 Subject: [PATCH 040/149] Include GCStress switch --- Switches.cs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Switches.cs b/Switches.cs index 44bf1e6..c6a9806 100644 --- a/Switches.cs +++ b/Switches.cs @@ -1,12 +1,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.VisualBasic.CompilerServices; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Antigen { @@ -85,6 +81,7 @@ public class Switches private static ComplusEnvVarGroup s_defaultGroup; private static ComplusEnvVarGroup s_jitStressGroup; private static ComplusEnvVarGroup s_jitStressRegsGroup; + private static ComplusEnvVarGroup s_gcStressGroup; private static ComplusEnvVarGroup s_hardwareGroup; private static ComplusEnvVarGroup s_commonVarGroup; @@ -123,7 +120,7 @@ public static void Initialize() s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoStructPromotion", new string[] { "0", "1", "2" }, 0.02)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoUnroll", s_onOffSwitch, 0.02)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackAllocToLocalSize", new string[] { "0", "1", "2", "4", "10", "16", "100"}, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitSkipArrayBoundCheck", s_onOffSwitch, 0.02)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitSkipArrayBoundCheck", s_onOffSwitch, 0.0002)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitSlowDebugChecksEnabled", s_onOffSwitch, 0.02)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitSplitFunctionSize", new string[] { "0", "1", "2", "4", "10", "16", "100" }, 0.01)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackChecks", s_onOffSwitch, 0.01)); @@ -141,8 +138,8 @@ public static void Initialize() s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoRedundantBranchOpts", s_onOffSwitch, 0.05)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoSsa", s_onOffSwitch, 0.05)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoValueNumber", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeat", new string[] { "*" }, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeatCount", new string[] { "1", "2", "5" }, 0.03)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeat", new string[] { "*" }, 0.0005)); + s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeatCount", new string[] { "1", "2", "5" }, 0.0003)); s_defaultGroup.AddVariable(new ComplusEnvVar("TailCallLoopOpt", s_onOffSwitch, 0.03)); s_defaultGroup.AddVariable(new ComplusEnvVar("FastTailCalls", s_onOffSwitch, 0.03)); s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableFinallyCloning", s_onOffSwitch, 0.03)); @@ -159,6 +156,10 @@ public static void Initialize() s_jitStressRegsGroup = new ComplusEnvVarGroup("JitStressRegs"); s_jitStressRegsGroup.AddVariable(new ComplusEnvVar("JitStressRegs", new string[] { "0", "1", "2", "3", "4", "8", "0x10", "0x80", "0x1000" }, 0.04)); + // GCStress + s_gcStressGroup = new ComplusEnvVarGroup("GCStress"); + s_gcStressGroup.AddVariable(new ComplusEnvVar("GCStress", new string[] { "0x3", "0xC", "0xF" }, 0.04)); + // Hardware s_hardwareGroup = new ComplusEnvVarGroup("Hardware"); s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAES", s_onOffSwitch, 0.02)); @@ -262,6 +263,13 @@ public static Dictionary TestVars() } } + // 30% of time add GCStress + if (PRNG.Decide(0.3)) + { + var envVar = s_gcStressGroup.GetRandomVariable(); + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + return envVars; } From 2f3f62d24aba15a917bd111fd633f80f929f9227 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:06:46 -0700 Subject: [PATCH 041/149] Improvements to TestRunner and Verifier --- Helpers/TestRunner.cs | 63 +++++++---- TestCase.cs | 241 ++++++++++++++++++++++++++++++------------ 2 files changed, 219 insertions(+), 85 deletions(-) diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index ea0519a..e1b75e4 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -15,14 +16,27 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CSharp; +using Newtonsoft.Json; namespace Antigen { public class TestRunner { private static TestRunner _testRunner; + private static readonly bool s_useDotnet = false; private RunOptions RunOptions; + private static readonly string s_corelibPath = typeof(object).Assembly.Location; + private static readonly MetadataReference[] s_references = + { + MetadataReference.CreateFromFile(s_corelibPath), + MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(s_corelibPath), "System.Console.dll")), + MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(s_corelibPath), "System.Runtime.dll")), + MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location), + MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location), + }; + private TestRunner(RunOptions runOptions) { RunOptions = runOptions; @@ -43,19 +57,10 @@ public static TestRunner GetInstance(RunOptions runOptions) /// internal CompileResult Compile(SyntaxTree programTree, string assemblyName) { - string corelibPath = typeof(object).Assembly.Location; - string otherAssembliesPath = Path.GetDirectoryName(corelibPath); - MetadataReference systemPrivateCorelib = MetadataReference.CreateFromFile(corelibPath); - MetadataReference systemConsole = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Console.dll")); - MetadataReference systemRuntime = MetadataReference.CreateFromFile(Path.Combine(otherAssembliesPath, "System.Runtime.dll")); - MetadataReference codeAnalysis = MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location); - MetadataReference csharpCodeAnalysis = MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location); - - MetadataReference[] references = { systemPrivateCorelib, systemConsole, systemRuntime, codeAnalysis, csharpCodeAnalysis }; - - var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, references, Switches.CompileOptions); string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{assemblyName}.exe"); + var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, Switches.CompileOptions); + using (var ms = new MemoryStream()) { EmitResult result; @@ -86,8 +91,14 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) internal string Execute(CompileResult compileResult, Dictionary environmentVariables) { Debug.Assert(compileResult.AssemblyFullPath != null); - if (false) + + if (s_useDotnet) { + foreach (var envVar in environmentVariables) + { + Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); + } + //TODO: if execute in debug vs. release dotnet.exe Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); Type testClassType = asm.GetType(compileResult.AssemblyName); @@ -116,6 +127,11 @@ internal string Execute(CompileResult compileResult, Dictionary sw.Close(); } + foreach (var envVar in environmentVariables) + { + Environment.SetEnvironmentVariable(envVar.Key, null, EnvironmentVariableTarget.Process); + } + return Encoding.UTF8.GetString(ms.ToArray()); } else @@ -127,7 +143,6 @@ internal string Execute(CompileResult compileResult, Dictionary WorkingDirectory = Environment.CurrentDirectory, RedirectStandardOutput = true, RedirectStandardError = true, - RedirectStandardInput = true, UseShellExecute = false, }; @@ -136,13 +151,25 @@ internal string Execute(CompileResult compileResult, Dictionary info.EnvironmentVariables[envVar.Key] = envVar.Value; } - using (Process proc = Process.Start(info)) + using (Process proc = new Process()) { - string results = proc.StandardOutput.ReadToEnd(); - results += proc.StandardError.ReadToEnd(); - proc.WaitForExit(1 * 60 * 1000); // 1 minute + proc.StartInfo = info; + + bool started = proc.Start(); + if (!started) + { + throw new Exception("Process not started"); + } + + // proc.StandardInput.Write(JsonConvert.SerializeObject(compileResult.Assembly)); + // proc.StandardInput.BaseStream.Write(compileResult.Assembly, 0, compileResult.Assembly.Length); + // proc.StandardInput.Close(); + + string output = proc.StandardOutput.ReadToEnd(); + string error = proc.StandardError.ReadToEnd(); - return results; + bool exited = proc.WaitForExit(30 * 1000); // 10 seconds + return exited ? output + error : "TIMEOUT"; } } } diff --git a/TestCase.cs b/TestCase.cs index 5c816da..9da6aac 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -16,19 +16,23 @@ using System.Runtime.CompilerServices; using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static System.Net.Mime.MediaTypeNames; namespace Antigen { public enum TestResult { CompileError, + KnownErrors, OutputMismatch, - Fail, - Pass + Assertion, + Pass, + OOM } public class TestCase { + private static int outputDiffHashCode = "Output diff".GetHashCode(); #region Compiler options public enum CompilationType @@ -48,6 +52,7 @@ public enum CompilationType }; private SyntaxNode testCaseRoot; + private static Dictionary uniqueIssues = new Dictionary(); //private List classesList; //private List methodsList; @@ -94,19 +99,20 @@ public void Generate() testCaseRoot = CompilationUnit() .WithUsings(usingDirective.ToSyntaxList()) - .WithMembers(new SyntaxList(klass)).NormalizeWhitespace(); + .WithMembers(new SyntaxList(klass)); } public TestResult Verify() { - SyntaxTree syntaxTree = RslnUtilities.GetValidSyntaxTree(testCaseRoot); + SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; // RslnUtilities.GetValidSyntaxTree(testCaseRoot); CompileResult compileResult = TestRunner.Compile(syntaxTree, Name); + StringBuilder fileContents; if (compileResult.AssemblyFullPath == null) { - StringBuilder fileContents = new StringBuilder(); + fileContents = new StringBuilder(); - fileContents.AppendLine(testCaseRoot.ToFullString()); + fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); fileContents.AppendLine("/*"); fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); foreach (var error in compileResult.CompileErrors) @@ -129,81 +135,66 @@ public TestResult Verify() var baselineVariables = Switches.BaseLineVars(); var testVariables = Switches.TestVars(); - string baseline = TestRunner.Execute(compileResult, baselineVariables); + // Execute test first and see if we have any errors/asserts string test = TestRunner.Execute(compileResult, testVariables); + string testAssertion = RslnUtilities.ParseAssertionError(test); - if (baseline == test) + // If OOM, skip + if (test.Contains("Out of memory")) { - try + SaveTestCase(testCaseRoot, null, null, test, testVariables, RunOptions.OutputDirectory, $"{Name}-oom"); + return TestResult.OOM; + } + // If assertion + else if (!string.IsNullOrEmpty(testAssertion)) + { + int assertionHashCode = testAssertion.GetHashCode(); + if (!uniqueIssues.ContainsKey(assertionHashCode)) { - File.Delete(compileResult.AssemblyFullPath); + uniqueIssues[assertionHashCode] = uniqueIssues.Count; } - catch (Exception) + + // Create hash of testAssertion and copy files in respective bucket. + string uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); + if (!Directory.Exists(uniqueIssueDirName)) { - // ignore errors + Directory.CreateDirectory(uniqueIssueDirName); } - return TestResult.Pass; - } - bool isKnownError = false; - foreach (string knownError in knownDiffs) + SaveTestCase(testCaseRoot, null, null, test, testVariables, uniqueIssueDirName, $"{Name}-fail"); + File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); + + return TestResult.Assertion; + } + else { - if (baseline.Contains(knownError) && test.Contains(knownError)) + foreach (string knownError in knownDiffs) { - isKnownError = true; - break; - } - } + if (test.Contains(knownError)) + { + try + { + File.Delete(compileResult.AssemblyFullPath); + } + catch (Exception) + { + // ignore errors + } - //TODO- for now, delete known error files - if (!isKnownError) - { - StringBuilder fileContents = new StringBuilder(); - fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVariables.ToList().Select(x => $"{x.Key}={x.Value}"))}"); - fileContents.AppendLine($"// TestVars: {string.Join("|", testVariables.ToList().Select(x => $"{x.Key}={x.Value}"))}"); - fileContents.AppendLine("//"); - fileContents.AppendLine(testCaseRoot.ToFullString()); - fileContents.AppendLine("/*"); + //TODO: Temporary - should delete once we fix all the knownerrors. + SaveTestCase(testCaseRoot, null, null, test, testVariables, RunOptions.OutputDirectory, $"{Name}-knownerrors"); - if (isKnownError) - { - fileContents.AppendLine($"Got known error mismatch:"); + return TestResult.KnownErrors; + } } - else - { - fileContents.AppendLine($"Got output diff:"); - } - fileContents.AppendLine("--------- Baseline ---------"); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - foreach (var envVars in baselineVariables) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - fileContents.AppendLine(); - fileContents.AppendLine(baseline); - - fileContents.AppendLine("--------- Test ---------"); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - foreach (var envVars in testVariables) - { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); - } - fileContents.AppendLine(); - fileContents.AppendLine(test); - fileContents.AppendLine("*/"); + } - string failedFileName = $"{Name}-{(isKnownError ? "known-error" : "fail")}"; - string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); - File.WriteAllText(failFile, fileContents.ToString()); - File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); - return TestResult.Fail; - } - else + string baseline = TestRunner.Execute(compileResult, baselineVariables); + string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); + + // Make sure baseline/test output is same + if (baseline == test) { try { @@ -213,10 +204,126 @@ public TestResult Verify() { // ignore errors } - return TestResult.OutputMismatch; + return TestResult.Pass; } + + string outputMismatchDirName = Path.Combine(RunOptions.OutputDirectory, "OutputMismatch"); + if (!Directory.Exists(outputMismatchDirName)) + { + Directory.CreateDirectory(outputMismatchDirName); + } + + SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, outputMismatchDirName, $"{Name}-fail"); + File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); + + return TestResult.OutputMismatch; + + + //foreach (string knownError in knownDiffs) + //{ + // if (baseline.Contains(knownError) && test.Contains(knownError)) + // { + // try + // { + // File.Delete(compileResult.AssemblyFullPath); + // } + // catch (Exception) + // { + // // ignore errors + // } + // SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, RunOptions.OutputDirectory, $"{Name}-knownerrors"); + + // return TestResult.KnownErrors; + // } + //} + + //if (baseline.Contains("Out of memory") || test.Contains("Out of memory")) + //{ + // SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, RunOptions.OutputDirectory, $"{Name}-oom"); + // return TestResult.OOM; + //} + + //if ((baseline == test) && string.IsNullOrEmpty(baselineAssertion)) + //{ + // try + // { + // File.Delete(compileResult.AssemblyFullPath); + // } + // catch (Exception) + // { + // // ignore errors + // } + // return TestResult.Pass; + //} + + //int assertionHashCode = testAssertion == null ? outputDiffHashCode : testAssertion.GetHashCode(); + //if (!uniqueIssues.ContainsKey(assertionHashCode)) + //{ + // uniqueIssues[assertionHashCode] = uniqueIssues.Count; + //} + + //// Create hash of testAssertion and copy files in respective bucket. + //string uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); + //if (!Directory.Exists(uniqueIssueDirName)) + //{ + // Directory.CreateDirectory(uniqueIssueDirName); + //} + + //SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, uniqueIssueDirName, $"{Name}-fail"); + + //File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); + //return string.IsNullOrEmpty(testAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; } + private void SaveTestCase( + SyntaxNode testCaseRoot, + string baselineOutput, + Dictionary baselineVars, + string testOutput, + Dictionary testVars, + string folderName, + string testFileName) + { + StringBuilder fileContents = new StringBuilder(); + if (baselineVars != null) + { + fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + } + fileContents.AppendLine($"// TestVars: {string.Join("|", testVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + fileContents.AppendLine("//"); + fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); + fileContents.AppendLine("/*"); + + fileContents.AppendLine($"Got output diff:"); + fileContents.AppendLine("--------- Baseline ---------"); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + if (baselineVars != null) + { + foreach (var envVars in baselineVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + } + fileContents.AppendLine(); + fileContents.AppendLine(baselineOutput); + + fileContents.AppendLine("--------- Test ---------"); + fileContents.AppendLine(); + fileContents.AppendLine("Environment:"); + fileContents.AppendLine(); + foreach (var envVars in testVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); +} + fileContents.AppendLine(); + fileContents.AppendLine(testOutput); + fileContents.AppendLine("*/"); + + string failFile = Path.Combine(folderName, $"{testFileName}.g.cs"); + File.WriteAllText(failFile, fileContents.ToString()); + } } } From 35122f3a3a7ce5a45f11648c1095244227d3df3a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:07:07 -0700 Subject: [PATCH 042/149] Track memory consumption --- Program.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Program.cs b/Program.cs index c9e150f..71dab8e 100644 --- a/Program.cs +++ b/Program.cs @@ -32,9 +32,11 @@ static void Main(string[] args) Dictionary stats = new Dictionary() { { TestResult.CompileError, 0 }, - { TestResult.Fail, 0 }, + { TestResult.Assertion, 0 }, + { TestResult.KnownErrors, 0 }, {TestResult.OutputMismatch, 0 }, {TestResult.Pass, 0 }, + {TestResult.OOM, 0 }, }; while (true) { @@ -42,8 +44,8 @@ static void Main(string[] args) testCase.Generate(); TestResult result = testCase.Verify(); stats[result]++; - Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. "); - if ((testId % 100) == 0) + Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); + if ((testId % 10) == 0) { foreach (var st in stats) { @@ -52,12 +54,11 @@ static void Main(string[] args) } Console.WriteLine(); testId++; - GC.Collect(); } } catch (OutOfMemoryException oom) { Console.WriteLine(oom.Message); - var myProcess = System.Diagnostics.Process.GetCurrentProcess(); + var myProcess = Process.GetCurrentProcess(); Console.WriteLine($" Physical memory usage : {myProcess.WorkingSet64}"); Console.WriteLine($" Base priority : {myProcess.BasePriority}"); Console.WriteLine($" Priority class : {myProcess.PriorityClass}"); From c5bfd2e5409ddd678047dba4fbdf48f4f79e5384 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:15:12 -0700 Subject: [PATCH 043/149] Remove references of NewtonSoft --- Antigen.csproj | 3 +-- Helpers/TestRunner.cs | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Antigen.csproj b/Antigen.csproj index 68061ba..dc11211 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -8,8 +8,7 @@ - - + diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index e1b75e4..032c8eb 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -11,13 +10,10 @@ using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using Antigen.Config; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; -using Microsoft.CSharp; -using Newtonsoft.Json; namespace Antigen { From 87d5aa767ac0a84948a8907a8aec674cd0743b3e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 14 Aug 2021 00:15:25 -0700 Subject: [PATCH 044/149] Fix regex of assertion --- Helpers/RslnUtilities.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Helpers/RslnUtilities.cs b/Helpers/RslnUtilities.cs index 14f5450..42fc9cd 100644 --- a/Helpers/RslnUtilities.cs +++ b/Helpers/RslnUtilities.cs @@ -18,7 +18,7 @@ namespace Antigen public class RslnUtilities { private static readonly Regex s_jitAssertionRegEx = new Regex("Assertion failed '(.*)' in '(.*)' during '(.*)'"); - private static readonly Regex s_coreclrAssertionRegEx = new Regex(@"Assert failure\(PID \d+ \[0x[0-9a-f]+], Thread: \d+ \[0x[0-9a-f]+]\):(.*)"); + private static readonly Regex s_coreclrAssertionRegEx = new Regex(@"Assert failure(\(PID \d+ \[0x[0-9a-f]+], Thread: \d+ \[0x[0-9a-f]+]\)):(.*)"); public static SyntaxTree GetValidSyntaxTree(SyntaxNode treeRoot, bool doValidation = true) @@ -96,13 +96,15 @@ internal static string ParseAssertionError(string output) assertionMatch = s_jitAssertionRegEx.Match(output); if (assertionMatch.Success) { - return assertionMatch.Value; + Debug.Assert(assertionMatch.Groups.Count == 4); + return assertionMatch.Groups[1].Value + ":" + assertionMatch.Groups[3].Value; } assertionMatch = s_coreclrAssertionRegEx.Match(output); if (assertionMatch.Success) { - return assertionMatch.Value; + Debug.Assert(assertionMatch.Groups.Count == 3); + return assertionMatch.Groups[2].Value; } return null; } From e65c6cddb61ac1a9f3b2f19692f22aa0838d6b47 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 07:30:43 -0700 Subject: [PATCH 045/149] Log depth during Annotation. --- TestMethod.cs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/TestMethod.cs b/TestMethod.cs index 7d57949..dce28f4 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -113,7 +113,7 @@ public virtual MethodDeclarationSyntax Generate() ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); - methodBody.Add(Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "var-init")); + methodBody.Add(Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "var-init", 0)); } // TODO-TEMP initialize one variable of each struct type @@ -138,7 +138,7 @@ public virtual MethodDeclarationSyntax Generate() methodBody.Add(Annotate(LocalDeclarationStatement( Helpers.GetVariableDeclaration(structType, variableName, - Helpers.GetObjectCreationExpression(structType.TypeName))), "struct-init")); + Helpers.GetObjectCreationExpression(structType.TypeName))), "struct-init", 0)); } // TODO-TEMP initialize out and ref method parameters @@ -166,7 +166,7 @@ public virtual MethodDeclarationSyntax Generate() ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.ReturnType, 0); ExpressionSyntax rhs = MethodCallHelper(nonLeafMethod, 0); - methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign")); + methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign", 0)); } // print all static variables @@ -293,7 +293,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } } - return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "VarDecl"); + return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "VarDecl", depth); } case StmtKind.IfElseStatement: { @@ -344,7 +344,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop 'else' body scope - return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "IfElse"); + return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "IfElse", depth); } case StmtKind.AssignStatement: { @@ -394,7 +394,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); } - return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); + return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign", depth); } case StmtKind.ForStatement: { @@ -438,7 +438,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop for-loop scope - return Annotate(Block(forStmt.Generate(false)), "for-loop"); + return Annotate(Block(forStmt.Generate(false)), "for-loop", depth); } case StmtKind.DoWhileStatement: { @@ -471,7 +471,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop do-while scope - return Annotate(Block(doStmt.Generate(false)), "do-while"); + return Annotate(Block(doStmt.Generate(false)), "do-while", depth); } case StmtKind.WhileStatement: { @@ -504,18 +504,18 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(); // pop while scope - return Annotate(Block(whileStmt.Generate(false)), "while-loop"); + return Annotate(Block(whileStmt.Generate(false)), "while-loop", depth); } case StmtKind.ReturnStatement: { Tree.ValueType returnType = MethodSignature.ReturnType; if (returnType.PrimitiveType == Primitive.Void) { - return Annotate(ReturnStatement(), "Return"); + return Annotate(ReturnStatement(), "Return", depth); } ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); - return Annotate(ReturnStatement(returnExpr), "Return"); + return Annotate(ReturnStatement(returnExpr), "Return", depth); } case StmtKind.TryCatchFinallyStatement: { @@ -699,10 +699,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) DefaultSwitchLabel())) .WithStatements(defaultBody.ToSyntaxList())); - return Annotate(SwitchStatement(switchExpr).WithSections(listOfCases.ToSyntaxList()), "SwitchCase"); + return Annotate(SwitchStatement(switchExpr).WithSections(listOfCases.ToSyntaxList()), "SwitchCase", depth); } default: - Debug.Assert(false, String.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); + Debug.Assert(false, string.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; } return null; @@ -847,7 +847,7 @@ public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string } Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); - return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign"); + return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign", 0); } private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) @@ -914,7 +914,7 @@ private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) #endif } - private StatementSyntax Annotate(StatementSyntax statement, string comment) + private StatementSyntax Annotate(StatementSyntax statement, string comment, int depth) { #if DEBUG string typeName = statement.GetType().Name; @@ -923,7 +923,7 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment) statementsCount[typeName] = 0; } statementsCount[typeName]++; - return statement.WithTrailingTrivia(TriviaList(Comment($"/* S#{statementsCount[typeName]}: {comment} */"))); + return statement.WithTrailingTrivia(TriviaList(Comment($"/* {depth}: S#{statementsCount[typeName]}: {comment} */"))); #else return statement; #endif From 9e0284cbe5eccfff74061e74b3583d14333f1c55 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 07:32:36 -0700 Subject: [PATCH 046/149] Foo(); --- TestClass.cs | 18 ++++++++++-------- TestMethod.cs | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/TestClass.cs b/TestClass.cs index ef63eca..b2b700f 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -44,14 +44,7 @@ public TestClass(TestCase tc, string className) public void RegisterMethod(MethodSignature methodSignature) { - double weight = 0.5; - if (methodSignature.MethodName.StartsWith("Leaf")) - { - // left methods have lower weight. try calling actual - // methods first. - weight = 0.20; - } - _methods.Add(new Weights(methodSignature, weight)); + _methods.Add(new Weights(methodSignature, (double) PRNG.Next(1, 100) / 100)); } /// @@ -73,6 +66,15 @@ public MethodSignature GetRandomMethod(Tree.ValueType returnType) return PRNG.WeightedChoice(matchingMethods); } + /// + /// Get random method that returns any type. + /// + /// + public MethodSignature GetRandomMethod() + { + return PRNG.WeightedChoice(_methods); + } + public Scope CurrentScope { get { return ScopeStack.Peek(); } diff --git a/TestMethod.cs b/TestMethod.cs index dce28f4..ef8b095 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -701,6 +701,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(SwitchStatement(switchExpr).WithSections(listOfCases.ToSyntaxList()), "SwitchCase", depth); } + case StmtKind.MethodCallStatement: + { + return Annotate(ExpressionStatement(MethodCallHelper(_testClass.GetRandomMethod(), depth)), "MethodCall", depth); ; + } default: Debug.Assert(false, string.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); break; From 0127c64c09cf2314981b5c0fd33ad0fb9d1f6c77 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 07:37:45 -0700 Subject: [PATCH 047/149] Add PreGenerated, Log() method --- Helpers/PreGenerated.cs | 105 ++++++++++++++++++++++++++++++++++++++++ TestCase.cs | 23 +-------- TestClass.cs | 25 +++++++--- TestMethod.cs | 10 ++-- Tree/Statements.cs | 2 +- 5 files changed, 131 insertions(+), 34 deletions(-) create mode 100644 Helpers/PreGenerated.cs diff --git a/Helpers/PreGenerated.cs b/Helpers/PreGenerated.cs new file mode 100644 index 0000000..d3a5b43 --- /dev/null +++ b/Helpers/PreGenerated.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen +{ + public static class PreGenerated + { + /// + /// Returns code related to using directives. + /// + public static List UsingDirective = + new List() + { + UsingDirective(IdentifierName("System")) + .WithUsingKeyword(Token(TriviaList(new[]{ + Comment("// Licensed to the .NET Foundation under one or more agreements."), + Comment("// The .NET Foundation licenses this file to you under the MIT license."), + Comment("// See the LICENSE file in the project root for more information."), + Comment("//"), + Comment("// This file is auto-generated."), + Comment("// Seed: " + PRNG.GetSeed()), + Comment("//"), + }), SyntaxKind.UsingKeyword, TriviaList())), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("System"), + IdentifierName("Collections")), + IdentifierName("Generic"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("System"), + IdentifierName("Runtime")), + IdentifierName("CompilerServices"))) + }; + + + private static List staticMethods = null; + + /// + /// Returns list of 3 static methods - Main, Log and PrintLog. + /// + public static List StaticMethods + { + get + { + if (staticMethods != null) + { + return staticMethods; + } + + MethodDeclarationSyntax mainMethod = (MethodDeclarationSyntax)ParseMemberDeclaration(@$"public static void Main(string[] args) {{ }}"); + MethodDeclarationSyntax loggerMethod = (MethodDeclarationSyntax)ParseMemberDeclaration( + $@"[MethodImpl(MethodImplOptions.NoInlining)] +public static void Log(string varName, object varValue) {{ + toPrint.Add($""{{varName}}={{varValue}}""); +}}"); + MethodDeclarationSyntax printLogMethod = (MethodDeclarationSyntax)ParseMemberDeclaration( + $@" +public static void PrintLog() {{ + foreach (var entry in toPrint) + {{ + Console.WriteLine(entry); + }} +}} +"); + + staticMethods = new List() + { + mainMethod, loggerMethod, printLogMethod + }; + return staticMethods; + } + } + + private static MemberDeclarationSyntax loggerVarDecl = null; + + /// + /// Returns declaration of logger variable + /// + public static MemberDeclarationSyntax LoggerVariableDecl + { + get + { + if (loggerVarDecl == null) + { + loggerVarDecl = ParseMemberDeclaration("private static List toPrint = new List();"); + } + return loggerVarDecl; + } + } + } +} diff --git a/TestCase.cs b/TestCase.cs index 9da6aac..5af12fa 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -74,31 +74,10 @@ public TestCase(int testId, RunOptions runOptions) public void Generate() { - List usingDirective = - new List() - { - UsingDirective(IdentifierName("System")) - .WithUsingKeyword(Token(TriviaList(new[]{ - Comment("// Licensed to the .NET Foundation under one or more agreements."), - Comment("// The .NET Foundation licenses this file to you under the MIT license."), - Comment("// See the LICENSE file in the project root for more information."), - Comment("//"), - Comment("// This file is auto-generated."), - Comment("// Seed: " + PRNG.GetSeed()), - Comment("//"), - }), SyntaxKind.UsingKeyword, TriviaList())), - UsingDirective( - QualifiedName( - QualifiedName( - IdentifierName("System"), - IdentifierName("Runtime")), - IdentifierName("CompilerServices"))) - }; - ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); testCaseRoot = CompilationUnit() - .WithUsings(usingDirective.ToSyntaxList()) + .WithUsings(PreGenerated.UsingDirective.ToSyntaxList()) .WithMembers(new SyntaxList(klass)); } diff --git a/TestClass.cs b/TestClass.cs index b2b700f..38e3fc3 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -191,12 +191,23 @@ private IList GenerateMethods() methods.Add(testMethod.Generate()); } methods.Add(new TestMethod(this, "Method0", true).Generate()); - methods.Add(ParseMemberDeclaration( -@$"public static void Main(string[] args) {{ - {ClassName} obj{ClassName} = new {ClassName}(); - obj{ClassName}.Method0(); -}} -")); + + var staticMethods = PreGenerated.StaticMethods; + var mainMethod = staticMethods[0]; + var loggerMethod = staticMethods[1]; + var printLogMethod = staticMethods[2]; + + mainMethod = mainMethod.WithBody( + Block( + ParseStatement($"{ClassName} obj{ClassName} = new {ClassName}();"), + ParseStatement($"obj{ClassName}.Method0();"), + ParseStatement("PrintLog();") + ) + ); + + methods.Add(mainMethod); + methods.Add(loggerMethod); + methods.Add(printLogMethod); return methods; } @@ -270,6 +281,8 @@ private IList GenerateStaticFields() LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10))))) .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + fields.Add(PreGenerated.LoggerVariableDecl); + return fields; } } diff --git a/TestMethod.cs b/TestMethod.cs index ef8b095..662e823 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -170,9 +170,9 @@ public virtual MethodDeclarationSyntax Generate() } // print all static variables - foreach (string variableName in _testClass.ClassScope.AllVariables) + foreach (var variableName in _testClass.ClassScope.AllVariables) { - methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); } } @@ -181,9 +181,9 @@ public virtual MethodDeclarationSyntax Generate() if (_stmtCount > 0) { // print all variables - foreach (string variableName in CurrentScope.AllVariables) + foreach (var variableName in CurrentScope.AllVariables) { - methodBody.Add(ParseStatement($"Console.WriteLine(\"{variableName}= \" + {variableName});")); + methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); } } @@ -615,7 +615,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(); // pop 'finally' body scope } - return Annotate(TryStatement(Block(tryBody), catchClauses.ToSyntaxList(), FinallyClause(Block(finallyBody))), "TryCatchFinally"); + return Annotate(TryStatement(Block(tryBody), catchClauses.ToSyntaxList(), FinallyClause(Block(finallyBody))), "TryCatchFinally", depth); } case StmtKind.SwitchStatement: { diff --git a/Tree/Statements.cs b/Tree/Statements.cs index 0de7ff9..a844669 100644 --- a/Tree/Statements.cs +++ b/Tree/Statements.cs @@ -11,7 +11,7 @@ public enum StmtKind ReturnStatement, TryCatchFinallyStatement, SwitchStatement, - //FunctionCallStatement, + MethodCallStatement, } //public class Statements From 753987710233f9975f9f3133c064b17e2d759199 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 07:40:05 -0700 Subject: [PATCH 048/149] Print variables after every block --- Statements/LoopStatement.cs | 7 +++- TestMethod.cs | 65 ++++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 18921b8..6d8075e 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -474,7 +474,7 @@ public int NumOfSecondaryInductionVariables { Name = "__loopSecondaryVar" + _nestNum + "_" + i, LoopParameters = TC.AstUtils.GetForBoundParameters(), - IsPrimary = PRNG.Decide(0.1) // Have 10% of extra primary induction variables + IsPrimary = PRNG.Decide(0.1) // Have 10% of extra primary induction variables }); } ValidateInductionVariablesParams(); @@ -528,6 +528,11 @@ public void AddToBody(StatementSyntax stmt) Body.Add(stmt); } + public void LogVariable(string name) + { + TestMethod.LogVariable(Body, name); + } + public LoopStatement(TestCase tc) { TC = tc; diff --git a/TestMethod.cs b/TestMethod.cs index 662e823..5c0ee65 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -1,4 +1,5 @@ -using Antigen.Statements; +using Antigen.Config; +using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -49,13 +50,28 @@ protected void PushScope(Scope scope) _testClass.PushScope(scope); } - protected Scope PopScope() + protected Scope PopScope(Action trackLocalVariables) { Scope ret = _testClass.PopScope(); - //Debug.Assert(ret.Parent == ScopeStack.Peek()); + + // Before poping, log the variables + foreach (var variableName in ret.AllVariables) + { + //TODO-config: Add MaxDepth in config + if (PRNG.Decide(0.8)) + { + trackLocalVariables(variableName); + } + } + return ret; } + internal static void LogVariable(IList stmtList, string variableName) + { + stmtList.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); + } + /// /// Register the method in enclosing class. /// @@ -151,7 +167,7 @@ public virtual MethodDeclarationSyntax Generate() for (int i = 0; i < _stmtCount; i++) { - StmtKind cur = GetASTUtils().GetRandomStatemet(); + StmtKind cur = GetASTUtils().GetRandomStatement(); methodBody.Add(StatementHelper(cur, 0)); } @@ -190,7 +206,7 @@ public virtual MethodDeclarationSyntax Generate() // return statement methodBody.Add(StatementHelper(StmtKind.ReturnStatement, 0)); - PopScope(); + PopScope(variableName => { }); RegisterMethod(MethodSignature); @@ -270,6 +286,14 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() .WithParameterList(ParameterList(SeparatedList(parameterNodes))); } + + /// + /// Generate statement of . It will generate terminal statement + /// if exceeds the threshold. + /// + /// + /// + /// public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { switch (stmtKind) @@ -322,7 +346,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } ifBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'if' body scope + PopScope(variableName => LogVariable(ifBody, variableName)); // pop 'if' body scope int elsecount = PRNG.Next(1, s_maxStatements); IList elseBody = new List(); @@ -342,7 +366,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } elseBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'else' body scope + PopScope(variableName => LogVariable(elseBody, variableName)); // pop 'else' body scope return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "IfElse", depth); } @@ -436,7 +460,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) forStmt.AddToBody(StatementHelper(cur, depth + 1)); } - PopScope(); // pop for-loop scope + PopScope(variableName => forStmt.LogVariable(variableName)); // pop for-loop scope return Annotate(Block(forStmt.Generate(false)), "for-loop", depth); } @@ -470,7 +494,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) doStmt.AddToBody(StatementHelper(cur, depth + 1)); } - PopScope(); // pop do-while scope + PopScope(variableName => doStmt.LogVariable(variableName)); // pop do-while scope return Annotate(Block(doStmt.Generate(false)), "do-while", depth); } case StmtKind.WhileStatement: @@ -503,7 +527,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) whileStmt.AddToBody(StatementHelper(cur, depth + 1)); } - PopScope(); // pop while scope + PopScope(variableName => whileStmt.LogVariable(variableName)); // pop while scope return Annotate(Block(whileStmt.Generate(false)), "while-loop", depth); } case StmtKind.ReturnStatement: @@ -546,7 +570,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } tryBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'try' body scope + PopScope(variableName => LogVariable(tryBody, variableName)); // pop 'try' body scope IList catchClauses = new List(); var allExceptions = Tree.ValueType.AllExceptions; @@ -585,7 +609,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } catchBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'catch' body scope + PopScope(variableName => LogVariable(catchBody, variableName)); // pop 'catch' body scope catchClauses.Add(CatchClause(CatchDeclaration(IdentifierName(exceptionToCatch.Name)), null, Block(catchBody))); } @@ -612,7 +636,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } finallyBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(); // pop 'finally' body scope + PopScope(variableName => LogVariable(finallyBody, variableName)); // pop 'finally' body scope } return Annotate(TryStatement(Block(tryBody), catchClauses.ToSyntaxList(), FinallyClause(Block(finallyBody))), "TryCatchFinally", depth); @@ -653,9 +677,9 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } caseBody.Add(StatementHelper(cur, depth + 1)); } - caseBody.Add(BreakStatement()); - PopScope(); // pop 'case' body scope + PopScope(variableName => LogVariable(caseBody, variableName)); // pop 'case' body scope + caseBody.Add(BreakStatement()); LiteralExpressionSyntax caseLiteralExpression; do @@ -689,8 +713,9 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } defaultBody.Add(StatementHelper(cur, depth + 1)); } + + PopScope(variableName => LogVariable(defaultBody, variableName)); // pop 'default' body scope defaultBody.Add(BreakStatement()); - PopScope(); // pop 'default' body scope listOfCases.Add( SwitchSection() @@ -712,6 +737,14 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return null; } + /// + /// Generate statement of that returns a value of + /// type. It will generate terminal expression if exceeds the threshold. + /// + /// + /// + /// + /// public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int depth) { switch (exprKind) From b3f3810cdf31aaa14ee654e813b288e71223fc63 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 08:02:52 -0700 Subject: [PATCH 049/149] Refactor TestRunner, Issue creation --- Helpers/RslnUtilities.cs | 4 +- Helpers/TestRunner.cs | 4 +- TestCase.cs | 172 +++++++++++++++------------------------ Trimmer/TestTrimmer.cs | 4 +- 4 files changed, 73 insertions(+), 111 deletions(-) diff --git a/Helpers/RslnUtilities.cs b/Helpers/RslnUtilities.cs index 42fc9cd..a0dbdca 100644 --- a/Helpers/RslnUtilities.cs +++ b/Helpers/RslnUtilities.cs @@ -85,9 +85,9 @@ internal static string ParseAssertionError(string output) } // If Fatal error, return text as it is. - if (output.Contains("Fatal error.")) + if (output.Contains("Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.")) { - return output; + return "Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."; } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 032c8eb..b79a2c3 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -84,7 +84,7 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) /// Execute the compiled assembly in an environment that has . /// /// - internal string Execute(CompileResult compileResult, Dictionary environmentVariables) + internal string Execute(CompileResult compileResult, Dictionary environmentVariables, int timeoutInSecs) { Debug.Assert(compileResult.AssemblyFullPath != null); @@ -164,7 +164,7 @@ internal string Execute(CompileResult compileResult, Dictionary string output = proc.StandardOutput.ReadToEnd(); string error = proc.StandardError.ReadToEnd(); - bool exited = proc.WaitForExit(30 * 1000); // 10 seconds + bool exited = proc.WaitForExit(timeoutInSecs * 1000); // 10 seconds return exited ? output + error : "TIMEOUT"; } } diff --git a/TestCase.cs b/TestCase.cs index 5af12fa..d754e76 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -105,44 +105,33 @@ public TestResult Verify() return TestResult.CompileError; } - //else - //{ - // string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); - // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); - //} +#if UNREACHABLE + else + { + string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); + File.WriteAllText(workingFile, testCaseRoot.ToFullString()); + } +#endif var baselineVariables = Switches.BaseLineVars(); var testVariables = Switches.TestVars(); // Execute test first and see if we have any errors/asserts - string test = TestRunner.Execute(compileResult, testVariables); + string test = TestRunner.Execute(compileResult, testVariables, 30); string testAssertion = RslnUtilities.ParseAssertionError(test); // If OOM, skip if (test.Contains("Out of memory")) { - SaveTestCase(testCaseRoot, null, null, test, testVariables, RunOptions.OutputDirectory, $"{Name}-oom"); +#if UNREACHABLE + SaveTestCase(testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-oom"); +#endif return TestResult.OOM; } - // If assertion + // If test assertion else if (!string.IsNullOrEmpty(testAssertion)) { - int assertionHashCode = testAssertion.GetHashCode(); - if (!uniqueIssues.ContainsKey(assertionHashCode)) - { - uniqueIssues[assertionHashCode] = uniqueIssues.Count; - } - - // Create hash of testAssertion and copy files in respective bucket. - string uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); - if (!Directory.Exists(uniqueIssueDirName)) - { - Directory.CreateDirectory(uniqueIssueDirName); - } - - SaveTestCase(testCaseRoot, null, null, test, testVariables, uniqueIssueDirName, $"{Name}-fail"); - File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); - + SaveTestCase(testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); return TestResult.Assertion; } else @@ -159,99 +148,49 @@ public TestResult Verify() { // ignore errors } - - //TODO: Temporary - should delete once we fix all the knownerrors. - SaveTestCase(testCaseRoot, null, null, test, testVariables, RunOptions.OutputDirectory, $"{Name}-knownerrors"); +#if UNREACHABLE + SaveTestCase(testCaseRoot, null, null, test, testVariables, knownError, $"{Name}-knownerrors"); +#endif return TestResult.KnownErrors; } } } - - string baseline = TestRunner.Execute(compileResult, baselineVariables); + string baseline = TestRunner.Execute(compileResult, baselineVariables, 30); string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); - // Make sure baseline/test output is same - if (baseline == test) + // If OOM, ignore this diff + if (baseline.Contains("Out of memory")) { - try - { - File.Delete(compileResult.AssemblyFullPath); - } - catch (Exception) - { - // ignore errors - } - return TestResult.Pass; +#if UNREACHABLE + SaveTestCase(testCaseRoot, baseline, baselineVariables, null, null, "Out of memory", $"{Name}-base-oom"); +#endif + return TestResult.OOM; } + // Is there assertion in baseline? + else if (!string.IsNullOrEmpty(baselineAssertion)) + { - string outputMismatchDirName = Path.Combine(RunOptions.OutputDirectory, "OutputMismatch"); - if (!Directory.Exists(outputMismatchDirName)) + SaveTestCase(testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); + return TestResult.Assertion; + } + // If baseline and test output doesn't match + else if (baseline != test) { - Directory.CreateDirectory(outputMismatchDirName); + SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{ Name}-output-mismatch"); + return TestResult.OutputMismatch; } - SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, outputMismatchDirName, $"{Name}-fail"); - File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); - - return TestResult.OutputMismatch; - - - //foreach (string knownError in knownDiffs) - //{ - // if (baseline.Contains(knownError) && test.Contains(knownError)) - // { - // try - // { - // File.Delete(compileResult.AssemblyFullPath); - // } - // catch (Exception) - // { - // // ignore errors - // } - // SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, RunOptions.OutputDirectory, $"{Name}-knownerrors"); - - // return TestResult.KnownErrors; - // } - //} - - //if (baseline.Contains("Out of memory") || test.Contains("Out of memory")) - //{ - // SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, RunOptions.OutputDirectory, $"{Name}-oom"); - // return TestResult.OOM; - //} - - //if ((baseline == test) && string.IsNullOrEmpty(baselineAssertion)) - //{ - // try - // { - // File.Delete(compileResult.AssemblyFullPath); - // } - // catch (Exception) - // { - // // ignore errors - // } - // return TestResult.Pass; - //} - - //int assertionHashCode = testAssertion == null ? outputDiffHashCode : testAssertion.GetHashCode(); - //if (!uniqueIssues.ContainsKey(assertionHashCode)) - //{ - // uniqueIssues[assertionHashCode] = uniqueIssues.Count; - //} - - //// Create hash of testAssertion and copy files in respective bucket. - //string uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); - //if (!Directory.Exists(uniqueIssueDirName)) - //{ - // Directory.CreateDirectory(uniqueIssueDirName); - //} - - //SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, uniqueIssueDirName, $"{Name}-fail"); - - //File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); - //return string.IsNullOrEmpty(testAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; + try + { + File.Delete(compileResult.AssemblyFullPath); + } + catch (Exception) + { + // ignore errors + } + return TestResult.Pass; } private void SaveTestCase( @@ -260,9 +199,32 @@ private void SaveTestCase( Dictionary baselineVars, string testOutput, Dictionary testVars, - string folderName, + string failureText, string testFileName) { + + string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; + string uniqueIssueDirName = null; + int assertionHashCode = failureText.GetHashCode(); + lock (this) + { + if (!uniqueIssues.ContainsKey(assertionHashCode)) + { + uniqueIssues[assertionHashCode] = uniqueIssues.Count; + } + + // Create hash of testAssertion and copy files in respective bucket. + uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); + if (!Directory.Exists(uniqueIssueDirName)) + { + Directory.CreateDirectory(uniqueIssueDirName); + File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), output); + } + } +#if DEBUG + File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); +#endif + StringBuilder fileContents = new StringBuilder(); if (baselineVars != null) { @@ -300,7 +262,7 @@ private void SaveTestCase( fileContents.AppendLine(testOutput); fileContents.AppendLine("*/"); - string failFile = Path.Combine(folderName, $"{testFileName}.g.cs"); + string failFile = Path.Combine(uniqueIssueDirName, $"{testFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); } diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 826ec56..c04f297 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -369,8 +369,8 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); //} - string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, Switches.BaseLineVars()); - string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars); + string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, Switches.BaseLineVars(), 10); + string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 10); TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; From 1a4feed2bf3bfca9d524ce8f79a974241740ec07 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 08:19:11 -0700 Subject: [PATCH 050/149] Adjust weights --- Config/ConfigOptions.cs | 11 ++++++++--- Helpers/Literals.cs | 31 ++++++++--------------------- TestCase.cs | 18 +++++++++++++++++ TestClass.cs | 2 +- TestMethod.cs | 44 ++++++++++++++++++++--------------------- 5 files changed, 57 insertions(+), 49 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 5d255e6..6215637 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -1,6 +1,7 @@ using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; @@ -16,6 +17,9 @@ public class ConfigOptions : OptionsBase { public const string WeightSuffix = "Weight"; + // Statement max depth + public const int MaxStmtDepth = 4; + // Expression weights public double LiteralWeight = 0.025; public double VariableWeight = 0.3; @@ -27,11 +31,12 @@ public class ConfigOptions : OptionsBase public double VariableDeclarationWeight = 0.03; //TODO: Reduce this and add aliases when we see this. public double IfElseStatementWeight = 0.2; public double AssignStatementWeight = 0.6; - public double ForStatementWeight = 0.3; - public double DoWhileStatementWeight = 0.2; - public double WhileStatementWeight = 0.3; + public double ForStatementWeight = 0.1; + public double DoWhileStatementWeight = 0.05; + public double WhileStatementWeight = 0.08; public double TryCatchFinallyStatementWeight = 0.4; public double SwitchStatementWeight = 0.1; + public double MethodCallStatementWeight = 0.4; // Type weights public double BooleanWeight = 0.3; diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index 79f5b1e..b266172 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -1,4 +1,5 @@ -using Antigen.Tree; +using Antigen.Config; +using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -14,24 +15,7 @@ namespace Antigen { public static partial class Helpers { - private static char[] Alphabet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - - private static IList> Numerals = new List>() - { - new Weights(int.MinValue, (double) PRNG.Next(1, 10) / 10000 ), - new Weights(int.MinValue + 1, (double)PRNG.Next(1, 10) / 10000 ), - new Weights(PRNG.Next(-100, -6), (double) PRNG.Next(1, 10) / 1000 ), - new Weights(-5, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(-2, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(-1, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(0, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(1, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(2, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(5, (double) PRNG.Next(1, 10) / 1000 ), - new Weights(PRNG.Next(6, 100), (double) PRNG.Next(1, 10) / 1000 ), - new Weights(int.MaxValue - 1, (double) PRNG.Next(1, 10) / 10000 ), - new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), - }; + public static char[] Alphabets = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; public static byte GetRandomByte() { @@ -70,16 +54,17 @@ public static ulong GetRandomULong() public static char GetRandomChar() { - return Alphabet[PRNG.Next(Alphabet.Length)]; + return Alphabets[PRNG.Next(Alphabets.Length)]; } public static string GetRandomString(int length = -1) { length = (length == -1) ? PRNG.Next(10) : length; StringBuilder strBuilder = new StringBuilder(); + for (int c = 0; c < length; c++) { - strBuilder.Append(Alphabet[PRNG.Next(Alphabet.Length)]); + strBuilder.Append(Alphabets[PRNG.Next(Alphabets.Length)]); } return strBuilder.ToString(); } @@ -109,7 +94,7 @@ public static decimal GetRandomDecimal() return (decimal)PRNG.Next(10) + (1 / PRNG.Next(1, 5)); } - public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType literalType) + public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType literalType, IList> numerals) { SyntaxToken literalToken; SyntaxKind kind; @@ -118,7 +103,7 @@ public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType litera { // numeric kind = SyntaxKind.NumericLiteralExpression; - int literalValue = PRNG.WeightedChoice(Numerals); + int literalValue = PRNG.WeightedChoice(numerals); // If unsigned, and number selected is negative, then flip it if ((literalType.PrimitiveType & Primitive.UnsignedInteger) != 0) diff --git a/TestCase.cs b/TestCase.cs index d754e76..f1e77df 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -54,6 +54,24 @@ public enum CompilationType private SyntaxNode testCaseRoot; private static Dictionary uniqueIssues = new Dictionary(); + internal IList> _numerals = new List>() + { + new Weights(int.MinValue, (double) PRNG.Next(1, 10) / 10000 ), + new Weights(int.MinValue + 1, (double)PRNG.Next(1, 10) / 10000 ), + new Weights(PRNG.Next(-100, -6), (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-5, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-2, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(-1, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(0, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(1, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(2, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(5, (double) PRNG.Next(1, 10) / 1000 ), + new Weights(PRNG.Next(6, 100), (double) PRNG.Next(1, 10) / 1000 ), + new Weights(int.MaxValue - 1, (double) PRNG.Next(1, 10) / 10000 ), + new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), + }; + + //private List classesList; //private List methodsList; //private List propertiesList; diff --git a/TestClass.cs b/TestClass.cs index 38e3fc3..29bc007 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -246,7 +246,7 @@ private IList GenerateStaticFields() { string variableName = "s_" + Helpers.GetVariableName(variableType, _variablesCount++); - ExpressionSyntax rhs = Helpers.GetLiteralExpression(variableType); + ExpressionSyntax rhs = Helpers.GetLiteralExpression(variableType, TC._numerals); CurrentScope.AddLocal(variableType, variableName); fields.Add(FieldDeclaration(Helpers.GetVariableDeclaration(variableType, variableName, rhs)) diff --git a/TestMethod.cs b/TestMethod.cs index 5c0ee65..9f6dc81 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -336,13 +336,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } ifBody.Add(StatementHelper(cur, depth + 1)); } @@ -356,13 +356,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } elseBody.Add(StatementHelper(cur, depth + 1)); } @@ -449,13 +449,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < n; ++i) { StmtKind cur; - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } forStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -483,13 +483,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < n; ++i) { StmtKind cur; - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } doStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -516,13 +516,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < n; ++i) { StmtKind cur; - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } whileStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -560,13 +560,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } tryBody.Add(StatementHelper(cur, depth + 1)); } @@ -599,13 +599,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } catchBody.Add(StatementHelper(cur, depth + 1)); } @@ -626,13 +626,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } finallyBody.Add(StatementHelper(cur, depth + 1)); } @@ -667,13 +667,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } caseBody.Add(StatementHelper(cur, depth + 1)); } @@ -703,13 +703,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { StmtKind cur; //TODO-config: Add MaxDepth in config - if (depth >= 2) + if (depth >= ConfigOptions.MaxStmtDepth) { cur = StmtKind.VariableDeclaration; } else { - cur = GetASTUtils().GetRandomStatemet(); + cur = GetASTUtils().GetRandomStatement(); } defaultBody.Add(StatementHelper(cur, depth + 1)); } @@ -751,7 +751,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i { case ExprKind.LiteralExpression: { - return Annotate(Helpers.GetLiteralExpression(exprType), "Literal"); + return Annotate(Helpers.GetLiteralExpression(exprType, TC._numerals), "Literal"); } case ExprKind.VariableExpression: @@ -797,7 +797,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i // errors during compiling the test case. if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) { - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType)), "BinOp-folded"); + return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType, TC._numerals)), "BinOp-folded"); } //TODO-config: Add MaxDepth in config From c2c50c80f48f530c41d5c142f72823a01fadef69 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 09:06:17 -0700 Subject: [PATCH 051/149] TerminalExpression and TerminalStatement --- Config/ConfigOptions.cs | 3 +- Helpers/RslnUtilities.cs | 2 +- TestCase.cs | 38 +++++++++---------- TestMethod.cs | 82 ++++++++++++++++++++++++++++++---------- Tree/AstUtils.cs | 50 ++++++++++++++++++++++-- 5 files changed, 129 insertions(+), 46 deletions(-) diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index 6215637..cbf01c6 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -19,12 +19,13 @@ public class ConfigOptions : OptionsBase // Statement max depth public const int MaxStmtDepth = 4; + public const int MaxExprDepth = 3; // Expression weights public double LiteralWeight = 0.025; public double VariableWeight = 0.3; public double BinaryOpWeight = 1; - public double MethodCallWeight = 0.23; + public double MethodCallWeight = 0.15; public double AssignWeight = 0.4; // Statement weights diff --git a/Helpers/RslnUtilities.cs b/Helpers/RslnUtilities.cs index a0dbdca..4ac85f8 100644 --- a/Helpers/RslnUtilities.cs +++ b/Helpers/RslnUtilities.cs @@ -25,7 +25,7 @@ public static SyntaxTree GetValidSyntaxTree(SyntaxNode treeRoot, bool doValidati { SyntaxTree validTree = CSharpSyntaxTree.ParseText(treeRoot.ToFullString()); -#if DEBUG +#if UNDEFINED if (doValidation) { SyntaxTree syntaxTree = treeRoot.SyntaxTree; diff --git a/TestCase.cs b/TestCase.cs index f1e77df..4eea507 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -32,7 +32,6 @@ public enum TestResult public class TestCase { - private static int outputDiffHashCode = "Output diff".GetHashCode(); #region Compiler options public enum CompilationType @@ -45,14 +44,14 @@ public enum CompilationType #region PreComputed roslyn syntax tress #endregion - private List knownDiffs = new List() + private readonly List _knownDiffs = new List() { "System.OverflowException: Value was either too large or too small for a Decimal.", "System.DivideByZeroException: Attempted to divide by zero.", }; private SyntaxNode testCaseRoot; - private static Dictionary uniqueIssues = new Dictionary(); + private static readonly Dictionary s_uniqueIssues = new(); internal IList> _numerals = new List>() { @@ -77,17 +76,17 @@ public enum CompilationType //private List propertiesList; //private List fieldsList; - private static TestRunner TestRunner; - private static RunOptions RunOptions; + private static TestRunner s_testRunner; + private static RunOptions s_runOptions; public string Name { get; private set; } public AstUtils AstUtils { get; private set; } public TestCase(int testId, RunOptions runOptions) { - RunOptions = runOptions; + s_runOptions = runOptions; AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; - TestRunner = TestRunner.GetInstance(RunOptions); + s_testRunner = TestRunner.GetInstance(s_runOptions); } public void Generate() @@ -103,7 +102,7 @@ public TestResult Verify() { SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; // RslnUtilities.GetValidSyntaxTree(testCaseRoot); - CompileResult compileResult = TestRunner.Compile(syntaxTree, Name); + CompileResult compileResult = s_testRunner.Compile(syntaxTree, Name); StringBuilder fileContents; if (compileResult.AssemblyFullPath == null) { @@ -118,7 +117,7 @@ public TestResult Verify() } fileContents.AppendLine("*/"); - string errorFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); + string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); File.WriteAllText(errorFile, fileContents.ToString()); return TestResult.CompileError; @@ -135,7 +134,7 @@ public TestResult Verify() var testVariables = Switches.TestVars(); // Execute test first and see if we have any errors/asserts - string test = TestRunner.Execute(compileResult, testVariables, 30); + string test = s_testRunner.Execute(compileResult, testVariables, 30); string testAssertion = RslnUtilities.ParseAssertionError(test); // If OOM, skip @@ -149,12 +148,12 @@ public TestResult Verify() // If test assertion else if (!string.IsNullOrEmpty(testAssertion)) { - SaveTestCase(testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); return TestResult.Assertion; } else { - foreach (string knownError in knownDiffs) + foreach (string knownError in _knownDiffs) { if (test.Contains(knownError)) { @@ -175,7 +174,7 @@ public TestResult Verify() } } - string baseline = TestRunner.Execute(compileResult, baselineVariables, 30); + string baseline = s_testRunner.Execute(compileResult, baselineVariables, 30); string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); // If OOM, ignore this diff @@ -190,13 +189,13 @@ public TestResult Verify() else if (!string.IsNullOrEmpty(baselineAssertion)) { - SaveTestCase(testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); return TestResult.Assertion; } // If baseline and test output doesn't match else if (baseline != test) { - SaveTestCase(testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{ Name}-output-mismatch"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{ Name}-output-mismatch"); return TestResult.OutputMismatch; } @@ -212,6 +211,7 @@ public TestResult Verify() } private void SaveTestCase( + string assemblyPath, SyntaxNode testCaseRoot, string baselineOutput, Dictionary baselineVars, @@ -226,13 +226,13 @@ private void SaveTestCase( int assertionHashCode = failureText.GetHashCode(); lock (this) { - if (!uniqueIssues.ContainsKey(assertionHashCode)) + if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { - uniqueIssues[assertionHashCode] = uniqueIssues.Count; + s_uniqueIssues[assertionHashCode] = s_uniqueIssues.Count; } // Create hash of testAssertion and copy files in respective bucket. - uniqueIssueDirName = Path.Combine(RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssues[assertionHashCode] }"); + uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{s_uniqueIssues[assertionHashCode] }"); if (!Directory.Exists(uniqueIssueDirName)) { Directory.CreateDirectory(uniqueIssueDirName); @@ -240,7 +240,7 @@ private void SaveTestCase( } } #if DEBUG - File.Move(compileResult.AssemblyFullPath, Path.Combine(RunOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); + File.Move(assemblyPath, Path.Combine(s_runOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); #endif StringBuilder fileContents = new StringBuilder(); diff --git a/TestMethod.cs b/TestMethod.cs index 9f6dc81..d779e4c 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -338,7 +338,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -358,7 +358,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -396,11 +396,11 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs = null; + ExpressionSyntax rhs; //TODO-config no. of attempts int noOfAttempts = 0; - while (noOfAttempts++ < 5) + do { rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); // Make sure that we do not end up with same lhs=lhs. @@ -408,7 +408,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { break; } - } + } while (noOfAttempts++ < 5); Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); // For division, make sure that divisor is not 0 @@ -451,7 +451,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) StmtKind cur; if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -485,7 +485,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) StmtKind cur; if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -518,7 +518,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) StmtKind cur; if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -562,7 +562,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -601,7 +601,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -628,7 +628,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -669,7 +669,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -705,7 +705,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-config: Add MaxDepth in config if (depth >= ConfigOptions.MaxStmtDepth) { - cur = StmtKind.VariableDeclaration; + cur = GetASTUtils().GetRandomTerminalStatement(); } else { @@ -782,9 +782,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i ExprKind lhsExprKind, rhsExprKind; //TODO-config: Add MaxDepth in config - if (depth >= 3) + if (depth >= ConfigOptions.MaxExprDepth) { - lhsExprKind = rhsExprKind = ExprKind.LiteralExpression; + lhsExprKind = GetRandomTerminalExpression(exprType); + rhsExprKind = GetRandomTerminalExpression(exprType); } else { @@ -825,11 +826,11 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs = null; + ExpressionSyntax rhs; //TODO-config no. of attempts int noOfAttempts = 0; - while (noOfAttempts++ < 5) + do { rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); // Make sure that we do not end up with same lhs=lhs. @@ -837,7 +838,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i { break; } - } + } while (noOfAttempts++ < 5); Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); // For division, make sure that divisor is not 0 @@ -869,11 +870,11 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string variableName) { ExpressionSyntax lhs = Annotate(Helpers.GetVariableAccessExpression(variableName), "specific-Var"); - ExpressionSyntax rhs = null; + ExpressionSyntax rhs; //TODO-config no. of attempts int noOfAttempts = 0; - while (noOfAttempts++ < 5) + do { rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(exprType.PrimitiveType), exprType, 0); // Make sure that we do not end up with same lhs=lhs. @@ -881,12 +882,51 @@ public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string { break; } - } + } while (noOfAttempts++ < 5); Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign", 0); } + /// + /// Makes sure to pick either a method call that has valid return type + /// or one of the variable or literal expression. + /// + /// + /// + private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) + { + ExprKind kind; + bool gotValidMethodCall = false; + + //TODO-config no. of attempts + int noOfAttempts = 0; + do + { + kind = GetASTUtils().GetRandomTerminalExpression(); + + if (kind != ExprKind.MethodCallExpression) + { + break; + } + + // If terminal expression is a method call, make sure we have a method that + // returns value of "exprType" + if (_testClass.GetRandomMethod(exprType) != null) + { + gotValidMethodCall = true; + break; + } + } while (noOfAttempts++ < 5); + + if (kind == ExprKind.MethodCallExpression && !gotValidMethodCall) + { + kind = PRNG.Decide(0.7) ? ExprKind.VariableExpression : ExprKind.LiteralExpression; + } + + return kind; + } + private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) { //MethodSignature methodSig = _testClass.GetRandomMethod(exprType); diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index b105d2e..477eb60 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -15,8 +15,8 @@ public class AstUtils private List> AllStatements = new List>(); private List> AllTypes = new List>(); private List> AllStatementsWithCFStmts = new List>(); - private List> AllTerminalExpressions = new List>(); - private List> AllTerminalStatements = new List>(); + private List> AllTerminalExpressions = new List>(); + private List> AllTerminalStatements = new List>(); private List> AllTerminalStatementsWithCFStmts = new List>(); private List> AllOperators = new List>(); @@ -45,7 +45,15 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // skip adding return as it will be added as the last statement of function continue; } - AllStatements.Add(new Weights(stmt, Options.Lookup(stmt))); + + var weight = new Weights(stmt, Options.Lookup(stmt)); + + AllStatements.Add(weight); + + if (stmt == StmtKind.AssignStatement || stmt == StmtKind.MethodCallStatement || stmt == StmtKind.VariableDeclaration) + { + AllTerminalStatements.Add(weight); + } } // Initialize expressions @@ -69,6 +77,11 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) { AllStructExpressions.Add(weight); } + + if (expr == ExprKind.LiteralExpression || expr == ExprKind.VariableExpression || expr == ExprKind.MethodCallExpression) + { + AllTerminalExpressions.Add(weight); + } } // Initialize operators @@ -129,6 +142,16 @@ from z in AllExpressions return PRNG.WeightedChoice(exprs); } + public ExprKind GetRandomTerminalExpression() + { + IEnumerable> exprs = + from z in AllTerminalExpressions + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(exprs); + } + public ExprKind GetRandomExpressionReturningPrimitive(Primitive returnPrimitiveType) { IEnumerable> exprs; @@ -156,7 +179,11 @@ public ExprKind GetRandomExpressionReturningPrimitive(Primitive returnPrimitiveT #region Random statement methods - public StmtKind GetRandomStatemet() + /// + /// Get random statement + /// + /// + public StmtKind GetRandomStatement() { // Select all appropriate statements IEnumerable> stmts = @@ -167,6 +194,21 @@ from z in AllStatements return PRNG.WeightedChoice(stmts); } + /// + /// Get random terminal statement + /// + /// + public StmtKind GetRandomTerminalStatement() + { + // Select all appropriate statements + IEnumerable> stmts = + from z in AllTerminalStatements + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(stmts); + } + #endregion #region Random operator methods From b794ba9f40f15846eed5d08168311fe545e321ac Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Aug 2021 09:06:58 -0700 Subject: [PATCH 052/149] Parallelize Antigen --- Program.cs | 104 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 28 deletions(-) diff --git a/Program.cs b/Program.cs index 71dab8e..9d2bd6c 100644 --- a/Program.cs +++ b/Program.cs @@ -1,7 +1,9 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using Antigen.Config; using Antigen.Trimmer; @@ -9,7 +11,19 @@ namespace Antigen { class Program { + static object SpinLock = new object(); public static RunOptions RunOptions = new RunOptions(); + private static readonly Dictionary s_stats = new Dictionary() + { + { TestResult.CompileError, 0 }, + { TestResult.Assertion, 0 }, + { TestResult.KnownErrors, 0 }, + {TestResult.OutputMismatch, 0 }, + {TestResult.Pass, 0 }, + {TestResult.OOM, 0 }, + }; + + private static int s_testId = 0; static void Main(string[] args) { @@ -28,34 +42,10 @@ static void Main(string[] args) return; } - int testId = 1; - Dictionary stats = new Dictionary() - { - { TestResult.CompileError, 0 }, - { TestResult.Assertion, 0 }, - { TestResult.KnownErrors, 0 }, - {TestResult.OutputMismatch, 0 }, - {TestResult.Pass, 0 }, - {TestResult.OOM, 0 }, - }; - while (true) - { - TestCase testCase = new TestCase(testId, RunOptions); - testCase.Generate(); - TestResult result = testCase.Verify(); - stats[result]++; - Console.Write($"Test# {testId} - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); - if ((testId % 10) == 0) - { - foreach (var st in stats) - { - Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); - } - } - Console.WriteLine(); - testId++; - } - } catch (OutOfMemoryException oom) + Parallel.For(0, 8, (p) => RunTest()); + + } + catch (OutOfMemoryException oom) { Console.WriteLine(oom.Message); var myProcess = Process.GetCurrentProcess(); @@ -69,5 +59,63 @@ static void Main(string[] args) Console.WriteLine($" Paged memory size : {myProcess.PagedMemorySize64}"); } } + + private static int GetNextTestId() + { + lock (SpinLock) + { + return ++s_testId; + } + } + + private static void SaveResult(Dictionary localStats) + { + lock (SpinLock) + { + foreach (var resultStat in localStats) + { + s_stats[resultStat.Key] += resultStat.Value; + } + + if ((s_stats.Count % 50) == 0) + { + Console.Write("** "); + foreach (var st in s_stats) + { + Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); + } + Console.WriteLine(); + } + } + } + + static void RunTest() + { + Dictionary localStats = new Dictionary() + { + { TestResult.CompileError, 0 }, + { TestResult.Assertion, 0 }, + { TestResult.KnownErrors, 0 }, + { TestResult.OutputMismatch, 0 }, + { TestResult.Pass, 0 }, + { TestResult.OOM, 0 }, + }; + + while (true) + { + int currTestId = GetNextTestId(); + TestCase testCase = new TestCase(currTestId, RunOptions); + testCase.Generate(); + TestResult result = testCase.Verify(); + Console.WriteLine($"Test# {currTestId} - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); + + localStats[result]++; + if (localStats.Count == 10) + { + SaveResult(localStats); + localStats.Clear(); + } + } + } } } From 4bacecadaa7b430fb5071d503076b92504f4ca95 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 21 Aug 2021 01:33:30 -0700 Subject: [PATCH 053/149] ConfigOptions and maxDepth fixup --- Antigen.csproj | 7 ++ Config/ConfigOptions.cs | 135 ++++++++++++++++---- Config/RunOptions.cs | 20 ++- Helpers/TestRunner.cs | 2 +- Program.cs | 21 ++-- README.md | 7 ++ TestCase.cs | 6 +- TestClass.cs | 16 +-- TestMethod.cs | 273 +++++++++++++++++++--------------------- Tree/AstUtils.cs | 29 ++--- 10 files changed, 310 insertions(+), 206 deletions(-) diff --git a/Antigen.csproj b/Antigen.csproj index dc11211..4ab89e9 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -10,10 +10,17 @@ + + + + PreserveNewest + + + diff --git a/Config/ConfigOptions.cs b/Config/ConfigOptions.cs index cbf01c6..a5636e8 100644 --- a/Config/ConfigOptions.cs +++ b/Config/ConfigOptions.cs @@ -9,17 +9,23 @@ namespace Antigen.Config { - public class OptionsBase + public class ConfigOptions { - } + private const string WeightSuffix = "Weight"; - public class ConfigOptions : OptionsBase - { - public const string WeightSuffix = "Weight"; + public string Name; + + // Test general configuration + public int MaxStmtDepth = 4; + public int MaxExprDepth = 3; - // Statement max depth - public const int MaxStmtDepth = 4; - public const int MaxExprDepth = 3; + public int MethodCount = 3; + public int MaxStatementCount = 10; + public int VariablesCount = 8; + public int StructCount = 2; + + // More controls + public int NumOfAttemptsForExpression = 5; // Expression weights public double LiteralWeight = 0.025; @@ -35,7 +41,7 @@ public class ConfigOptions : OptionsBase public double ForStatementWeight = 0.1; public double DoWhileStatementWeight = 0.05; public double WhileStatementWeight = 0.08; - public double TryCatchFinallyStatementWeight = 0.4; + public double TryCatchFinallyStatementWeight = 0.08; public double SwitchStatementWeight = 0.1; public double MethodCallStatementWeight = 0.4; @@ -101,32 +107,117 @@ public class ConfigOptions : OptionsBase public double EqualsWeight = 0.8; public double NotEqualsWeight = 0.8; - // Config options - // Probablity of removing loop parameters -- see comments on BoundParameters in ForStatement + /// + /// Probablity of removing loop parameters -- see comments on BoundParameters in ForStatement + /// public double LoopParametersRemovalProbability = 0.1; - // Probability of having forward loop whose induction variable always increases + /// + /// Probability of having forward loop whose induction variable always increases + /// public double LoopForwardProbability = 0.7; - //Probabilty whether loop induction variable should start from loop invariant value or +/- 3 + /// + /// Probabilty whether loop induction variable should start from loop invariant value or +/- 3 + /// public double LoopStartFromInvariantProbabilty = 0.5; - //Probabilty whether loop step should happen pre or post break condition + /// + /// Probabilty whether loop step should happen pre or post break condition + /// public double LoopStepPreBreakCondProbability = 0.5; - // Probability of usage of array.length vs. loopinvariant + /// + /// Probability of usage of array.length vs. loopinvariant + /// public double UseLoopInvariantVariableProbability = 1.0; // Always have 1.0 for now to stop making .length as invariant because that could lead to long loops - // This will put loop condition at the end of the loop body. - // Always use ContinueStatementWeight = 0 if this is true (see lessmath_no_continue.xml), otherwise there is a chance of infinite loop here. - // This is a quick fix for now. We need to come up with a better solution for this for IE11. + /// + /// This will put loop condition at the end of the loop body. + /// Always use ContinueStatementWeight = 0 if this is true (see lessmath_no_continue.xml), otherwise there is a chance of infinite loop here. + /// This is a quick fix for now. We need to come up with a better solution for this for IE11. + /// public bool AllowLoopCondAtEnd = false; - // number of testcases to create - public long NumTestCases = 1; + /// + /// Nested struct probability + /// + public double NestedStructProbability = 0.2; + + /// + /// Field count of structs + /// + public int StructFieldCount = 4; + + /// + /// Nested struct depth + /// + public int NestedStructDepth = 2; + + /// + /// Probability of field type being struct + /// + public double StructFieldTypeProbability = 0.2; + + /// + /// Struct variable declaration which is alias of existing variable + /// + public double StructAliasProbability = 0.2; + + /// + /// Log local variables in a block probability + /// + public double LocalVariablesLogProbability = 0.5; + + /// + /// Number of catch clauses + /// + public int CatchClausesCount = 2; - // max number of statements in a block - public int MaxStatements = 5; + /// + /// Finally clause probabiliy + /// + public double FinallyClauseProbability = 0.5; + + /// + /// Parameter passing probability - None. + /// + public double ParamPassingNoneProbability = 0.6; + + /// + /// Parameter passing probability - Ref. + /// + public double ParamPassingRefProbability = 0.2; + + /// + /// Parameter passing probability - Out. + /// + public double ParamPassingOutProbability = 0.2; + + /// + /// Leaf methods NoInline probability. + /// + public double LeafMethodsNoInlineProbability = 0.4; + + /// + /// Maximum no. of method parameters + /// + public int MaxMethodParametersCount = 10; + + /// + /// Struct usage probability + /// + public double StructUsageProbability = 0.4; + + /// + /// Maximum number of case counts in switch statement + /// + public int MaxCaseCounts = 4; + + public override string ToString() + { + return Name; + } public double Lookup(Tree.ValueType type) { diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index 4841d1a..bf9e9f0 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -1,13 +1,16 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; namespace Antigen.Config { - public class RunOptions : OptionsBase + public class RunOptions { // random seed public int Seed = -1; @@ -19,11 +22,20 @@ public class RunOptions : OptionsBase public long NumTestCases = 0; // Duration to execute tests for (overrides number specified in each XML config file) - public ulong SecondsToRun = 0; + public int HoursToRun = 0; - // Full path to CoreRun.exe + [NonSerialized()] public string CoreRun = null; - public readonly string MainMethodName = "Main"; + public List Configs; + + internal static RunOptions Initialize() + { + string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string antiGenConfig = Path.Combine(currentDirectory, "Config", "antigen.json"); + Debug.Assert(File.Exists(antiGenConfig)); + + return JsonConvert.DeserializeObject(File.ReadAllText(antiGenConfig)); + } } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index b79a2c3..3853760 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -98,7 +98,7 @@ internal string Execute(CompileResult compileResult, Dictionary //TODO: if execute in debug vs. release dotnet.exe Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); Type testClassType = asm.GetType(compileResult.AssemblyName); - MethodInfo mainMethodInfo = testClassType.GetMethod(RunOptions.MainMethodName); + MethodInfo mainMethodInfo = testClassType.GetMethod("Main"); Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); Exception ex = null; diff --git a/Program.cs b/Program.cs index 9d2bd6c..6394e7b 100644 --- a/Program.cs +++ b/Program.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading.Tasks; using Antigen.Config; @@ -11,8 +12,8 @@ namespace Antigen { class Program { - static object SpinLock = new object(); - public static RunOptions RunOptions = new RunOptions(); + static readonly object s_spinLock = new object(); + private static readonly RunOptions s_runOptions = RunOptions.Initialize(); private static readonly Dictionary s_stats = new Dictionary() { { TestResult.CompileError, 0 }, @@ -29,20 +30,20 @@ static void Main(string[] args) { try { - PRNG.Initialize(RunOptions.Seed); + PRNG.Initialize(s_runOptions.Seed); Switches.Initialize(); - RunOptions.CoreRun = args[0]; + s_runOptions.CoreRun = args[0]; // trimmer if (args.Length > 1) { string testCaseToTrim = args[1]; - TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, RunOptions); + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, s_runOptions); testTrimmer.Trim(); return; } - Parallel.For(0, 8, (p) => RunTest()); + Parallel.For(0, 1, (p) => RunTest()); } catch (OutOfMemoryException oom) @@ -62,7 +63,7 @@ static void Main(string[] args) private static int GetNextTestId() { - lock (SpinLock) + lock (s_spinLock) { return ++s_testId; } @@ -70,7 +71,7 @@ private static int GetNextTestId() private static void SaveResult(Dictionary localStats) { - lock (SpinLock) + lock (s_spinLock) { foreach (var resultStat in localStats) { @@ -104,10 +105,10 @@ static void RunTest() while (true) { int currTestId = GetNextTestId(); - TestCase testCase = new TestCase(currTestId, RunOptions); + TestCase testCase = new TestCase(currTestId, s_runOptions); testCase.Generate(); TestResult result = testCase.Verify(); - Console.WriteLine($"Test# {currTestId} - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); + Console.WriteLine($"Test# {currTestId} [{testCase.Config.Name}] - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); localStats[result]++; if (localStats.Count == 10) diff --git a/README.md b/README.md index 34eda94..1cd1d45 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,10 @@ C# test generator and RyuJIT tester - Named after Covid-19 antigen test. 14. try-catch-finally 15. switch-case 16. Environment variables list + +TODO: +- Arrays +- Various configurations +- CSEs +- Classes +- CI pipeline \ No newline at end of file diff --git a/TestCase.cs b/TestCase.cs index 4eea507..95f65e2 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -78,12 +78,16 @@ public enum CompilationType private static TestRunner s_testRunner; private static RunOptions s_runOptions; + + internal ConfigOptions Config { get; private set; } public string Name { get; private set; } public AstUtils AstUtils { get; private set; } public TestCase(int testId, RunOptions runOptions) { s_runOptions = runOptions; + Config = s_runOptions.Configs[PRNG.Next(s_runOptions.Configs.Count)]; + AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; s_testRunner = TestRunner.GetInstance(s_runOptions); @@ -253,7 +257,7 @@ private void SaveTestCase( fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); fileContents.AppendLine("/*"); - fileContents.AppendLine($"Got output diff:"); + fileContents.AppendLine($"Config: {Config.Name}"); fileContents.AppendLine("--------- Baseline ---------"); fileContents.AppendLine(); fileContents.AppendLine("Environment:"); diff --git a/TestClass.cs b/TestClass.cs index 29bc007..c93c9b2 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -119,8 +119,7 @@ private List GenerateStructs() { List structs = new List(); - //TODO:config - number of structs - for (int structIndex = 1; structIndex <= 5; structIndex++) + for (int structIndex = 1; structIndex <= TC.Config.StructCount; structIndex++) { string structName = $"S{structIndex}"; var (structDecl, fields) = GenerateStruct(structName, structName, structIndex, 1); @@ -135,13 +134,10 @@ private List GenerateStructs() List fieldsTree = new List(); List fieldsMetadata = new List(); - //TODO: config - number of fields - int fieldCount = PRNG.Next(1, 5); + int fieldCount = PRNG.Next(1, TC.Config.StructFieldCount); for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) { - //TODO:config - probability of nested structs - //TODO:config - struct nested depth - if (PRNG.Decide(0.1) && depth < 3) + if (PRNG.Decide(TC.Config.NestedStructProbability) && depth < TC.Config.NestedStructDepth) { string nestedStructName = $"S{structIndex}_D{depth}_F{fieldIndex}"; string nestedStructType = structType + "." + nestedStructName; @@ -155,8 +151,7 @@ private List GenerateStructs() Tree.ValueType fieldType; string fieldName; - //TODO:config - probability of fields of type struct - if (PRNG.Decide(0.3) && CurrentScope.NumOfStructTypes > 0) + if (PRNG.Decide(TC.Config.StructFieldTypeProbability) && CurrentScope.NumOfStructTypes > 0) { fieldType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; } @@ -184,8 +179,7 @@ private IList GenerateMethods() { List methods = new List(); - //TODO-config: No. of methods per class - for (int i = 1; i < 2; i++) + for (int i = 1; i < TC.Config.MethodCount; i++) { var testMethod = new TestMethod(this, "Method" + i); methods.Add(testMethod.Generate()); diff --git a/TestMethod.cs b/TestMethod.cs index d779e4c..0a493bb 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -21,14 +21,12 @@ public class TestMethod private readonly TestClass _testClass; private TestCase TC => _testClass.TC; protected readonly string Name; - protected readonly int _stmtCount; + private readonly List> _valuePassing; - //TODO-config: Move this to ConfigOptions - private static readonly int s_maxStatements = 8; #if DEBUG - private Dictionary expressionsCount = new Dictionary(); - private Dictionary statementsCount = new Dictionary(); + private readonly Dictionary _expressionsCount = new(); + private readonly Dictionary _statementsCount = new(); #endif private int _variablesCount = 0; @@ -57,8 +55,7 @@ protected Scope PopScope(Action trackLocalVariables) // Before poping, log the variables foreach (var variableName in ret.AllVariables) { - //TODO-config: Add MaxDepth in config - if (PRNG.Decide(0.8)) + if (PRNG.Decide(TC.Config.LocalVariablesLogProbability)) { trackLocalVariables(variableName); } @@ -83,12 +80,11 @@ protected void RegisterMethod(MethodSignature methodSignature) /// /// Creates leaf method that does not take parameters and has a single return statement. /// - protected TestMethod(TestClass enclosingClass, string methodName, int stmtCount) + protected TestMethod(TestClass enclosingClass, string methodName) { _testClass = enclosingClass; Name = methodName; MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); - _stmtCount = stmtCount; } /// @@ -103,9 +99,13 @@ public TestMethod(TestClass enclosingClass, string methodName, bool isMainInvoca Name = methodName; MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); _isMainInvocation = isMainInvocation; - - //TODO-config: Statements in a function - _stmtCount = PRNG.Next(1, s_maxStatements); + _valuePassing = new() + { + new Weights(ParamValuePassing.None, TC.Config.ParamPassingNoneProbability), + new Weights(ParamValuePassing.Ref, TC.Config.ParamPassingRefProbability), + new Weights(ParamValuePassing.Out, TC.Config.ParamPassingOutProbability), + //new Weights(ParamValuePassing.In, 10), + }; } public virtual MethodDeclarationSyntax Generate() @@ -118,12 +118,6 @@ public virtual MethodDeclarationSyntax Generate() // TODO-TEMP initialize one variable of each type foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { - //TODO-config: Only declare again 20% of variables - if (PRNG.Decide(0.8)) - { - continue; - } - string variableName = Helpers.GetVariableName(variableType, _variablesCount++); ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); @@ -135,12 +129,6 @@ public virtual MethodDeclarationSyntax Generate() // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { - //TODO-config: Only declare again 20% of variables - if (PRNG.Decide(0.8)) - { - continue; - } - string variableName = Helpers.GetVariableName(structType, _variablesCount++); CurrentScope.AddLocal(structType, variableName); @@ -155,6 +143,27 @@ public virtual MethodDeclarationSyntax Generate() methodBody.Add(Annotate(LocalDeclarationStatement( Helpers.GetVariableDeclaration(structType, variableName, Helpers.GetObjectCreationExpression(structType.TypeName))), "struct-init", 0)); + + if (!PRNG.Decide(TC.Config.StructAliasProbability)) + { + continue; + } + + var aliasVariableName = Helpers.GetVariableName(structType, _variablesCount++); + + CurrentScope.AddLocal(structType, aliasVariableName); + + // Add all the fields to the scope + listOfStructFields = CurrentScope.GetStructFields(structType); + foreach (var structField in listOfStructFields) + { + CurrentScope.AddLocal(structField.FieldType, $"{aliasVariableName}.{structField.FieldName}"); + } + + methodBody.Add(Annotate(LocalDeclarationStatement( + Helpers.GetVariableDeclaration(structType, aliasVariableName, + Helpers.GetVariableAccessExpression(variableName))), "struct-alias-init", 0)); + } // TODO-TEMP initialize out and ref method parameters @@ -165,7 +174,7 @@ public virtual MethodDeclarationSyntax Generate() CurrentScope.AddLocal(param.ParamType, param.ParamName); } - for (int i = 0; i < _stmtCount; i++) + for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); i++) { StmtKind cur = GetASTUtils().GetRandomStatement(); methodBody.Add(StatementHelper(cur, 0)); @@ -192,15 +201,10 @@ public virtual MethodDeclarationSyntax Generate() } } - // If only statement in method is a return statement, - // do not print the variables we generated above. - if (_stmtCount > 0) + // print all variables + foreach (var variableName in CurrentScope.AllVariables) { - // print all variables - foreach (var variableName in CurrentScope.AllVariables) - { - methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); - } + methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); } // return statement @@ -223,9 +227,8 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() int numOfParameters = 0; if (!_isMainInvocation) { - //TODO:config - No. of parameters - numOfParameters = PRNG.Next(1, 10); - MethodSignature.ReturnType = GetRandomExprType(structProbability: 0.7); + numOfParameters = PRNG.Next(1, TC.Config.MaxMethodParametersCount); + MethodSignature.ReturnType = GetRandomExprType(); } List parameters = new List(); @@ -234,8 +237,8 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() for (int paramIndex = 0; paramIndex < numOfParameters; paramIndex++) { - var paramType = GetRandomExprType(structProbability: 0.7); - var passingWay = PRNG.WeightedChoice(MethodSignature.ValuePassing); + var paramType = GetRandomExprType(); + var passingWay = PRNG.WeightedChoice(_valuePassing); string paramName = "p_" + Helpers.GetVariableName(paramType, paramIndex); // Add parameters to the scope except the one that is marked as OUT @@ -300,7 +303,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { case StmtKind.VariableDeclaration: { - Tree.ValueType variableType = GetRandomExprType(structProbability: 0.3); + Tree.ValueType variableType = GetRandomExprType(); string variableName = Helpers.GetVariableName(variableType, _variablesCount++); @@ -321,22 +324,22 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.IfElseStatement: { + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); Scope ifBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); Scope elseBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); - //TODO-config: Add MaxDepth in config - int ifcount = PRNG.Next(1, s_maxStatements); + int ifcount = PRNG.Next(1, TC.Config.MaxStatementCount); IList ifBody = new List(); PushScope(ifBranchScope); for (int i = 0; i < ifcount; i++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -348,15 +351,14 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(ifBody, variableName)); // pop 'if' body scope - int elsecount = PRNG.Next(1, s_maxStatements); + int elsecount = PRNG.Next(1, TC.Config.MaxStatementCount); IList elseBody = new List(); PushScope(elseBranchScope); for (int i = 0; i < elsecount; i++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -395,21 +397,19 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) rhsExprType = lhsExprType; } - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs; - //TODO-config no. of attempts - int noOfAttempts = 0; - do + ExprKind rhsKind; + if (depth >= TC.Config.MaxExprDepth) { - rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); - // Make sure that we do not end up with same lhs=lhs. - if (lhs.ToFullString() != rhs.ToFullString()) - { - break; - } - } while (noOfAttempts++ < 5); - Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); + rhsKind = GetRandomTerminalExpression(rhsExprType); + } + else + { + rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + } + + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); + ExpressionSyntax rhs = ExprHelper(rhsKind, rhsExprType, 0); // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) @@ -422,10 +422,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.ForStatement: { + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + Scope forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); ForStatement forStmt = new ForStatement(TC); - //TODO:config - int n = PRNG.Next(1, s_maxStatements); forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); forStmt.NestNum = depth; forStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -446,10 +446,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label - for (int i = 0; i < n; ++i) + for (int i = 0; i < TC.Config.MaxStatementCount; ++i) { StmtKind cur; - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -466,10 +466,11 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.DoWhileStatement: { + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); DoWhileStatement doStmt = new DoWhileStatement(TC); - //TODO:config - int n = PRNG.Next(1, s_maxStatements); + doStmt.NestNum = depth; doStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -480,10 +481,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label - for (int i = 0; i < n; ++i) + for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -499,10 +500,11 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.WhileStatement: { + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); WhileStatement whileStmt = new WhileStatement(TC); - //TODO:config - int n = PRNG.Next(1, s_maxStatements); + whileStmt.NestNum = depth; whileStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); @@ -513,10 +515,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label - for (int i = 0; i < n; ++i) + for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -538,29 +540,27 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) return Annotate(ReturnStatement(), "Return", depth); } - ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, depth); + ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, 0); return Annotate(ReturnStatement(returnExpr), "Return", depth); } case StmtKind.TryCatchFinallyStatement: { - //TODO-config: Add MaxDepth in config - int catchCounts = PRNG.Next(0, 3); + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + + int catchCounts = PRNG.Next(0, TC.Config.CatchClausesCount); - //TODO-config: Add finally weight in config // If there are no catch, then definitely add finally, otherwise skip it. - bool hasFinally = catchCounts == 0 || PRNG.Decide(0.5); + bool hasFinally = catchCounts == 0 || PRNG.Decide(TC.Config.FinallyClauseProbability); IList tryBody = new List(); Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(tryScope); - //TODO-config: Add MaxDepth in config - int tryStmtCount = PRNG.Next(1, s_maxStatements); + int tryStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); for (int i = 0; i < tryStmtCount; i++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -587,19 +587,16 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } caughtExceptions.Add(exceptionToCatch); - //TODO-config: Add MaxDepth in config - int catchStmtCount = PRNG.Next(1, s_maxStatements / 2); + int catchStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); IList catchBody = new List(); Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(catchScope); - //TODO-config: Add MaxDepth in config for (int i = 0; i < catchStmtCount; i++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -620,13 +617,11 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(finallyScope); - //TODO-config: Add MaxDepth in config - int finallyStmtCount = PRNG.Next(1, s_maxStatements); + int finallyStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); for (int i = 0; i < finallyStmtCount; i++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -643,8 +638,9 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.SwitchStatement: { - //TODO-config: Add CaseCount in config - int caseCount = PRNG.Next(2, 10); + Debug.Assert(depth <= TC.Config.MaxStmtDepth); + + int caseCount = PRNG.Next(1, TC.Config.MaxCaseCounts); Primitive switchType = new Primitive[] { Primitive.Int, Primitive.Long, Primitive.Char, Primitive.String }[PRNG.Next(4)]; Tree.ValueType switchExprType = Tree.ValueType.ForPrimitive(switchType); @@ -659,15 +655,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Scope caseScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(caseScope); - //TODO-config: Add no. of case statemets in config // Generate statements within each cases - int caseStmtCount = PRNG.Next(1, 3); + int caseStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); IList caseBody = new List(); for (int j = 0; j < caseStmtCount; j++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -702,8 +696,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int j = 0; j < defaultStmtCount; j++) { StmtKind cur; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxStmtDepth) + if (depth >= TC.Config.MaxStmtDepth) { cur = GetASTUtils().GetRandomTerminalStatement(); } @@ -761,6 +754,8 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i case ExprKind.BinaryOpExpression: { + Debug.Assert(depth <= TC.Config.MaxExprDepth); + Primitive returnType = exprType.PrimitiveType; Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); @@ -781,8 +776,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } ExprKind lhsExprKind, rhsExprKind; - //TODO-config: Add MaxDepth in config - if (depth >= ConfigOptions.MaxExprDepth) + if (depth >= TC.Config.MaxExprDepth) { lhsExprKind = GetRandomTerminalExpression(exprType); rhsExprKind = GetRandomTerminalExpression(exprType); @@ -801,9 +795,8 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType, TC._numerals)), "BinOp-folded"); } - //TODO-config: Add MaxDepth in config - ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth >= 5 ? 0 : depth + 1); - ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth >= 5 ? 0 : depth + 1); + ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth + 1); + ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth + 1); // For division, make sure that divisor is not 0 if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) @@ -816,6 +809,8 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } case ExprKind.AssignExpression: { + Debug.Assert(depth <= TC.Config.MaxExprDepth); + Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(returnPrimitiveType: exprType.PrimitiveType); Tree.ValueType lhsExprType, rhsExprType; lhsExprType = rhsExprType = exprType; @@ -825,21 +820,19 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth); - ExpressionSyntax rhs; - //TODO-config no. of attempts - int noOfAttempts = 0; - do + ExprKind rhsKind; + if (depth >= TC.Config.MaxExprDepth) { - rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType), rhsExprType, depth); - // Make sure that we do not end up with same lhs=lhs. - if (lhs.ToFullString() != rhs.ToFullString()) - { - break; - } - } while (noOfAttempts++ < 5); - Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); + rhsKind = GetRandomTerminalExpression(rhsExprType); + } + else + { + rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + } + + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); + ExpressionSyntax rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); // For division, make sure that divisor is not 0 if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) @@ -872,8 +865,7 @@ public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string ExpressionSyntax lhs = Annotate(Helpers.GetVariableAccessExpression(variableName), "specific-Var"); ExpressionSyntax rhs; - //TODO-config no. of attempts - int noOfAttempts = 0; + int noOfAttempts = TC.Config.NumOfAttemptsForExpression; do { rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(exprType.PrimitiveType), exprType, 0); @@ -899,8 +891,7 @@ private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) ExprKind kind; bool gotValidMethodCall = false; - //TODO-config no. of attempts - int noOfAttempts = 0; + int noOfAttempts = TC.Config.NumOfAttemptsForExpression; do { kind = GetASTUtils().GetRandomTerminalExpression(); @@ -921,7 +912,14 @@ private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) if (kind == ExprKind.MethodCallExpression && !gotValidMethodCall) { - kind = PRNG.Decide(0.7) ? ExprKind.VariableExpression : ExprKind.LiteralExpression; + if (exprType.PrimitiveType == Primitive.Struct) + { + kind = ExprKind.VariableExpression; + } + else + { + kind = PRNG.Decide(0.7) ? ExprKind.VariableExpression : ExprKind.LiteralExpression; + } } return kind; @@ -929,7 +927,6 @@ private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) { - //MethodSignature methodSig = _testClass.GetRandomMethod(exprType); List argumentNodes = new List(); int paramsCount = methodSig.Parameters.Count; @@ -940,7 +937,7 @@ private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) Tree.ValueType argType = parameter.ParamType; ExprKind argExprKind = parameter.PassingWay == ParamValuePassing.None ? GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType) : ExprKind.VariableExpression; - ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth); + ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth + 1); ArgumentSyntax argSyntax = Argument(argExpr); if (parameter.PassingWay == ParamValuePassing.Ref) @@ -963,10 +960,9 @@ private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) .WithArgumentList(ArgumentList(SeparatedList(argumentNodes))); } - private Tree.ValueType GetRandomExprType(double structProbability) + private Tree.ValueType GetRandomExprType() { - //TODO:config - probability of struct variables - if (PRNG.Decide(structProbability) && CurrentScope.NumOfStructTypes > 0) + if (PRNG.Decide(TC.Config.StructUsageProbability) && CurrentScope.NumOfStructTypes > 0) { return CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; } @@ -980,12 +976,12 @@ private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) { #if DEBUG string typeName = expression.GetType().Name; - if (!expressionsCount.ContainsKey(typeName)) + if (!_expressionsCount.ContainsKey(typeName)) { - expressionsCount[typeName] = 0; + _expressionsCount[typeName] = 0; } - expressionsCount[typeName]++; - return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{expressionsCount[typeName]}: {comment} */"))); + _expressionsCount[typeName]++; + return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{_expressionsCount[typeName]}: {comment} */"))); #else return expression; #endif @@ -995,12 +991,12 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment, int { #if DEBUG string typeName = statement.GetType().Name; - if (!statementsCount.ContainsKey(typeName)) + if (!_statementsCount.ContainsKey(typeName)) { - statementsCount[typeName] = 0; + _statementsCount[typeName] = 0; } - statementsCount[typeName]++; - return statement.WithTrailingTrivia(TriviaList(Comment($"/* {depth}: S#{statementsCount[typeName]}: {comment} */"))); + _statementsCount[typeName]++; + return statement.WithTrailingTrivia(TriviaList(Comment($"/* {depth}: S#{_statementsCount[typeName]}: {comment} */"))); #else return statement; #endif @@ -1014,15 +1010,6 @@ public class MethodSignature public List Parameters; public bool IsLeaf; - //TODO:config - public static List> ValuePassing = new() - { - new Weights(ParamValuePassing.None, 50), - new Weights(ParamValuePassing.Ref, 25), - new Weights(ParamValuePassing.Out, 15), - //new Weights(ParamValuePassing.In, 10), - }; - public MethodSignature(string methodName, bool isLeaf = false) { MethodName = methodName; @@ -1088,7 +1075,7 @@ public class TestLeafMethod : TestMethod { private Tree.ValueType _returnType; public TestLeafMethod(TestClass enclosingClass, string methodName, Tree.ValueType returnType) - : base(enclosingClass, methodName, 0) + : base(enclosingClass, methodName) { _returnType = returnType; } diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 477eb60..2c87c22 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -20,21 +20,21 @@ public class AstUtils private List> AllTerminalStatementsWithCFStmts = new List>(); private List> AllOperators = new List>(); - private ConfigOptions Options; + private ConfigOptions ConfigOptions; private RunOptions RunOptions; private TestCase TestCase; private Weights MethodCallWeight; public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) { - Options = configOptions; + ConfigOptions = configOptions; RunOptions = runOptions; TestCase = tc; // Initialize types foreach (ValueType type in ValueType.GetTypes()) { - AllTypes.Add(new Weights(type, Options.Lookup(type))); + AllTypes.Add(new Weights(type, ConfigOptions.Lookup(type))); } // Initialize statements @@ -46,7 +46,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) continue; } - var weight = new Weights(stmt, Options.Lookup(stmt)); + var weight = new Weights(stmt, ConfigOptions.Lookup(stmt)); AllStatements.Add(weight); @@ -59,7 +59,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize expressions foreach (ExprKind expr in (ExprKind[])Enum.GetValues(typeof(ExprKind))) { - var weight = new Weights(expr, Options.Lookup(expr)); ; + var weight = new Weights(expr, ConfigOptions.Lookup(expr)); ; if (expr == ExprKind.MethodCallExpression) { MethodCallWeight = weight; @@ -87,7 +87,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize operators foreach (Operator oper in Operator.GetOperators()) { - AllOperators.Add(new Weights(oper, Options.Lookup(oper))); + AllOperators.Add(new Weights(oper, ConfigOptions.Lookup(oper))); } } @@ -287,21 +287,22 @@ where z.Data.HasFlag(OpFlags.String) return PRNG.WeightedChoice(ops); } + //TODO: Move this into LoopStatement internal LoopControlParameters GetForBoundParameters() { LoopControlParameters Ret = new LoopControlParameters(); - Ret.IsInitInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); - Ret.IsStepInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); - Ret.IsBreakCondInLoopHeader = PRNG.Decide(Options.LoopParametersRemovalProbability); + Ret.IsInitInLoopHeader = PRNG.Decide(ConfigOptions.LoopParametersRemovalProbability); + Ret.IsStepInLoopHeader = PRNG.Decide(ConfigOptions.LoopParametersRemovalProbability); + Ret.IsBreakCondInLoopHeader = PRNG.Decide(ConfigOptions.LoopParametersRemovalProbability); - Ret.IsLoopInvariantVariableUsed = PRNG.Decide(Options.UseLoopInvariantVariableProbability); - Ret.IsBreakCondAtEndOfLoopBody = Options.AllowLoopCondAtEnd ? PRNG.Decide(0.5) : false; - Ret.IsForwardLoop = PRNG.Decide(Options.LoopForwardProbability); - Ret.IsLoopStartFromInvariant = PRNG.Decide(Options.LoopStartFromInvariantProbabilty); + Ret.IsLoopInvariantVariableUsed = PRNG.Decide(ConfigOptions.UseLoopInvariantVariableProbability); + Ret.IsBreakCondAtEndOfLoopBody = ConfigOptions.AllowLoopCondAtEnd ? PRNG.Decide(0.5) : false; + Ret.IsForwardLoop = PRNG.Decide(ConfigOptions.LoopForwardProbability); + Ret.IsLoopStartFromInvariant = PRNG.Decide(ConfigOptions.LoopStartFromInvariantProbabilty); Ret.LoopInductionChangeFactor = PRNG.Next(1, 5); Ret.LoopInitValueVariation = PRNG.Next(0, Ret.LoopInductionChangeFactor); - Ret.IsStepBeforeBreakCondition = PRNG.Decide(Options.LoopStepPreBreakCondProbability); + Ret.IsStepBeforeBreakCondition = PRNG.Decide(ConfigOptions.LoopStepPreBreakCondProbability); // Generate operator for break condition in a forward loop // Depending on the loop type/condition, we will later flip the operator in LoopStatement From d8550bf131aee3cb9d7cb109869eccdc8e9130d6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 22 Aug 2021 00:34:54 -0700 Subject: [PATCH 054/149] Fix timeout --- Helpers/TestRunner.cs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 3853760..87976a2 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -157,15 +157,31 @@ internal string Execute(CompileResult compileResult, Dictionary throw new Exception("Process not started"); } - // proc.StandardInput.Write(JsonConvert.SerializeObject(compileResult.Assembly)); - // proc.StandardInput.BaseStream.Write(compileResult.Assembly, 0, compileResult.Assembly.Length); - // proc.StandardInput.Close(); + StringBuilder output = new StringBuilder(); + proc.OutputDataReceived += new DataReceivedEventHandler((s, e) => + { + output.AppendLine(e.Data); + }); + + proc.ErrorDataReceived += new DataReceivedEventHandler((s, e) => + { + output.AppendLine(e.Data); + }); - string output = proc.StandardOutput.ReadToEnd(); - string error = proc.StandardError.ReadToEnd(); + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); bool exited = proc.WaitForExit(timeoutInSecs * 1000); // 10 seconds - return exited ? output + error : "TIMEOUT"; + if (!exited) + { + try + { + proc.Kill(true); + } + catch { } + return "TIMEOUT"; + } + return output.ToString(); } } } From ffe8c60031cd6b6db33231cd3e9570b250a8c456 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 22 Aug 2021 00:35:19 -0700 Subject: [PATCH 055/149] Fix the depth --- TestClass.cs | 23 ++++++- TestMethod.cs | 178 +++++++++++++++++++++++++++++++------------------- 2 files changed, 131 insertions(+), 70 deletions(-) diff --git a/TestClass.cs b/TestClass.cs index c93c9b2..c7f532a 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -44,7 +44,7 @@ public TestClass(TestCase tc, string className) public void RegisterMethod(MethodSignature methodSignature) { - _methods.Add(new Weights(methodSignature, (double) PRNG.Next(1, 100) / 100)); + _methods.Add(new Weights(methodSignature, (double)PRNG.Next(1, 100) / 100)); } /// @@ -52,6 +52,11 @@ public void RegisterMethod(MethodSignature methodSignature) /// public List AllNonLeafMethods => _methods.Where(m => !m.Data.IsLeaf).Select(m => m.Data).ToList(); + /// + /// Returns all leaf methods + /// + public List AllLeafMethods => _methods.Where(m => m.Data.IsLeaf).Select(m => m.Data).ToList(); + /// /// Get random method that returns specfic returnType. Null if no such /// method is generated yet. @@ -66,6 +71,22 @@ public MethodSignature GetRandomMethod(Tree.ValueType returnType) return PRNG.WeightedChoice(matchingMethods); } + /// + /// Gets random leaf method that returns specific returnType. Null if no such + /// method is generated yet. + /// + /// + /// + public MethodSignature GetRandomLeafMethod(Tree.ValueType returnType) + { + var matchingMethods = _methods.Where(m => m.Data.IsLeaf).Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); + if (matchingMethods.Count == 0) + { + return null; + } + return PRNG.WeightedChoice(matchingMethods); + } + /// /// Get random method that returns any type. /// diff --git a/TestMethod.cs b/TestMethod.cs index 0a493bb..9e61cad 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -299,6 +299,8 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() /// public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); + switch (stmtKind) { case StmtKind.VariableDeclaration: @@ -324,7 +326,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.IfElseStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); @@ -339,13 +341,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < ifcount; i++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } ifBody.Add(StatementHelper(cur, depth + 1)); } @@ -358,13 +360,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < elsecount; i++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } elseBody.Add(StatementHelper(cur, depth + 1)); } @@ -397,17 +399,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) rhsExprType = lhsExprType; } - - ExprKind rhsKind; - if (depth >= TC.Config.MaxExprDepth) - { - rhsKind = GetRandomTerminalExpression(rhsExprType); - } - else - { - rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); - } - + ExprKind rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); ExpressionSyntax rhs = ExprHelper(rhsKind, rhsExprType, 0); @@ -422,7 +414,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.ForStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Scope forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); ForStatement forStmt = new ForStatement(TC); @@ -449,13 +441,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < TC.Config.MaxStatementCount; ++i) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } forStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -466,7 +458,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.DoWhileStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); DoWhileStatement doStmt = new DoWhileStatement(TC); @@ -484,13 +476,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } doStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -500,7 +492,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.WhileStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); WhileStatement whileStmt = new WhileStatement(TC); @@ -518,13 +510,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } whileStmt.AddToBody(StatementHelper(cur, depth + 1)); } @@ -545,7 +537,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.TryCatchFinallyStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); int catchCounts = PRNG.Next(0, TC.Config.CatchClausesCount); @@ -560,13 +552,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < tryStmtCount; i++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } tryBody.Add(StatementHelper(cur, depth + 1)); } @@ -596,13 +588,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < catchStmtCount; i++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } catchBody.Add(StatementHelper(cur, depth + 1)); } @@ -621,13 +613,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int i = 0; i < finallyStmtCount; i++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } finallyBody.Add(StatementHelper(cur, depth + 1)); } @@ -638,7 +630,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.SwitchStatement: { - Debug.Assert(depth <= TC.Config.MaxStmtDepth); + //Debug.Assert(depth <= TC.Config.MaxStmtDepth); int caseCount = PRNG.Next(1, TC.Config.MaxCaseCounts); @@ -661,13 +653,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int j = 0; j < caseStmtCount; j++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } caseBody.Add(StatementHelper(cur, depth + 1)); } @@ -696,13 +688,13 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) for (int j = 0; j < defaultStmtCount; j++) { StmtKind cur; - if (depth >= TC.Config.MaxStmtDepth) + if (depth < TC.Config.MaxStmtDepth) { - cur = GetASTUtils().GetRandomTerminalStatement(); + cur = GetASTUtils().GetRandomStatement(); } else { - cur = GetASTUtils().GetRandomStatement(); + cur = GetASTUtils().GetRandomTerminalStatement(); } defaultBody.Add(StatementHelper(cur, depth + 1)); } @@ -721,7 +713,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.MethodCallStatement: { - return Annotate(ExpressionStatement(MethodCallHelper(_testClass.GetRandomMethod(), depth)), "MethodCall", depth); ; + return Annotate(ExpressionStatement(MethodCallHelper(_testClass.GetRandomMethod(), 0)), "MethodCall", depth); ; } default: Debug.Assert(false, string.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -740,6 +732,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) /// public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int depth) { + //Debug.Assert(depth <= TC.Config.MaxExprDepth); + switch (exprKind) { case ExprKind.LiteralExpression: @@ -754,7 +748,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i case ExprKind.BinaryOpExpression: { - Debug.Assert(depth <= TC.Config.MaxExprDepth); + //Debug.Assert(depth <= TC.Config.MaxExprDepth); Primitive returnType = exprType.PrimitiveType; @@ -776,15 +770,15 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } ExprKind lhsExprKind, rhsExprKind; - if (depth >= TC.Config.MaxExprDepth) + if (depth < TC.Config.MaxExprDepth) { - lhsExprKind = GetRandomTerminalExpression(exprType); - rhsExprKind = GetRandomTerminalExpression(exprType); + lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); + rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); } else { - lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); - rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + lhsExprKind = GetRandomTerminalExpression(exprType); + rhsExprKind = GetRandomTerminalExpression(exprType); } // Fold arithmetic binop expressions that has constants. @@ -809,7 +803,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } case ExprKind.AssignExpression: { - Debug.Assert(depth <= TC.Config.MaxExprDepth); + //Debug.Assert(depth <= TC.Config.MaxExprDepth); Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(returnPrimitiveType: exprType.PrimitiveType); Tree.ValueType lhsExprType, rhsExprType; @@ -822,13 +816,13 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i ExprKind rhsKind; - if (depth >= TC.Config.MaxExprDepth) + if (depth < TC.Config.MaxExprDepth) { - rhsKind = GetRandomTerminalExpression(rhsExprType); + rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); } else { - rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + rhsKind = GetRandomTerminalExpression(rhsExprType); } ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); @@ -846,7 +840,14 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i } case ExprKind.MethodCallExpression: { - return MethodCallHelper(_testClass.GetRandomMethod(exprType), depth); + if (depth < TC.Config.MaxExprDepth) + { + return MethodCallHelper(_testClass.GetRandomMethod(exprType), depth + 1); + } + else + { + return MethodCallHelper(_testClass.GetRandomLeafMethod(exprType), depth + 1); + } } default: @@ -889,28 +890,51 @@ public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) { ExprKind kind; - bool gotValidMethodCall = false; int noOfAttempts = TC.Config.NumOfAttemptsForExpression; + bool found = false; + do { kind = GetASTUtils().GetRandomTerminalExpression(); - - if (kind != ExprKind.MethodCallExpression) + switch (kind) { - break; + case ExprKind.LiteralExpression: + { + if (exprType.PrimitiveType != Primitive.Struct) + { + found = true; + } + break; + } + case ExprKind.VariableExpression: + { + found = true; + break; + } + case ExprKind.MethodCallExpression: + { + // If terminal expression is a method call, make sure we have a method that + // returns value of "exprType" + if (_testClass.GetRandomMethod(exprType) != null) + { + found = true; + break; + } + break; + } + default: + throw new Exception("Unsupported terminal expression"); + } - // If terminal expression is a method call, make sure we have a method that - // returns value of "exprType" - if (_testClass.GetRandomMethod(exprType) != null) + if (found) { - gotValidMethodCall = true; break; } } while (noOfAttempts++ < 5); - if (kind == ExprKind.MethodCallExpression && !gotValidMethodCall) + if (!found) { if (exprType.PrimitiveType == Primitive.Struct) { @@ -935,7 +959,23 @@ private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) MethodParam parameter = methodSig.Parameters[paramId]; Tree.ValueType argType = parameter.ParamType; - ExprKind argExprKind = parameter.PassingWay == ParamValuePassing.None ? GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType) : ExprKind.VariableExpression; + ExprKind argExprKind; + + if (parameter.PassingWay == ParamValuePassing.None) + { + if (depth < TC.Config.MaxExprDepth) + { + argExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType); + } + else + { + argExprKind = GetRandomTerminalExpression(argType); + } + } + else + { + argExprKind = ExprKind.VariableExpression; + } ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth + 1); ArgumentSyntax argSyntax = Argument(argExpr); From 32a4e3b39dd1f2cb4340cf926df5474bd5d3a359 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 22 Aug 2021 00:35:26 -0700 Subject: [PATCH 056/149] fix trimmer --- Trimmer/TestTrimmer.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index c04f297..f47c9ea 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -91,12 +91,11 @@ public void TrimTree() do { trimmedAtleastOne = false; + trimmedAtleastOne |= TrimEnvVars(); trimmedAtleastOne |= TrimStatements(); trimmedAtleastOne |= TrimExpressions(); - trimmedAtleastOne |= TrimEnvVars(); } while (trimmedAtleastOne); - } /// @@ -164,17 +163,18 @@ public bool TrimExpressions() }; - bool trimmedAtleastOne = false; - bool trimmedInCurrIter; + //bool trimmedAtleastOne = false; + //bool trimmedInCurrIter; - do - { - trimmedInCurrIter = false; - trimmedInCurrIter |= Trim(trimmerList); - trimmedAtleastOne |= trimmedInCurrIter; - } while (trimmedInCurrIter); + //do + //{ + // trimmedInCurrIter = false; + // trimmedInCurrIter |= Trim(trimmerList); + // trimmedAtleastOne |= trimmedInCurrIter; + //} while (trimmedInCurrIter); - return trimmedAtleastOne; + //return trimmedAtleastOne; + return Trim(trimmerList); } public bool TrimEnvVars() From d0a8db9887e0ee16465bd6b3b8da495de4f4e133 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 22 Aug 2021 23:43:10 -0700 Subject: [PATCH 057/149] Move ComPlusEnv vars to json --- Config/EnvVarOptions.cs | 176 ++++++++++ Config/RunOptions.cs | 9 +- Config/antigen.json | 708 ++++++++++++++++++++++++++++++++++++++++ Helpers/TestRunner.cs | 2 +- Program.cs | 1 - Switches.cs | 279 ---------------- TestCase.cs | 4 +- 7 files changed, 895 insertions(+), 284 deletions(-) create mode 100644 Config/EnvVarOptions.cs create mode 100644 Config/antigen.json delete mode 100644 Switches.cs diff --git a/Config/EnvVarOptions.cs b/Config/EnvVarOptions.cs new file mode 100644 index 0000000..06c6f96 --- /dev/null +++ b/Config/EnvVarOptions.cs @@ -0,0 +1,176 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen.Config +{ + public static class EnvVarOptions + { + internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); + + private static List s_baselineGroups; + private static readonly List> s_baselineGroupWeight = new(); + + private static List s_testGroups; + private static readonly List> s_testGroupWeight = new(); + + internal static void Initialize(List baselineEnvVars, List testEnvVars) + { + s_baselineGroups = baselineEnvVars; + foreach (var base_group in s_baselineGroups) + { + s_baselineGroupWeight.Add(new Weights(base_group, base_group.Weight)); + base_group.PopulateWeights(); + } + + s_testGroups = testEnvVars; + foreach (var test_group in s_testGroups) + { + s_testGroupWeight.Add(new Weights(test_group, test_group.Weight)); + test_group.PopulateWeights(); + } + } + + /// + /// Returns a random EnvVarGroup depending on the weight. + /// + /// + private static ComplusEnvVarGroup GetRandomTestGroup() + { + return PRNG.WeightedChoice(s_testGroupWeight); + } + + /// + /// Returns random set of baseline environment variables. + /// + /// + public static Dictionary BaseLineVars() + { + var envVars = new Dictionary(); + foreach (var group in s_baselineGroups) + { + foreach (var variable in group.Variables) + { + envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; + } + } + return envVars; + } + + /// + /// Returns random set of test environment variables. + /// + /// + public static Dictionary TestVars() + { + var envVars = new Dictionary() + { + { "COMPlus_TieredCompilation", "0"} + }; + + var defaultGroup = s_testGroups.First(tg => tg.Name == "Default"); + // default variables + var usedEnvVars = new HashSet(); + var defaultVariablesCount = PRNG.Next(1, 8); + for (var i = 0; i < defaultVariablesCount; i++) + { + ComplusEnvVar envVar; + + // Avoid duplicate variables + do + { + envVar = defaultGroup.GetRandomVariable(); + } while (!usedEnvVars.Add(envVar.Name)); + + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + + var stressVariablesCount = PRNG.Next(1, 4); + for (var i = 0; i < stressVariablesCount; i++) + { + ComplusEnvVar envVar; + + // Avoid duplicate variables + do + { + var stressGroup = GetRandomTestGroup(); + envVar = stressGroup.GetRandomVariable(); + } while (!usedEnvVars.Add(envVar.Name)); + + envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + } + + return envVars; + } + } + + public class ComplusEnvVar + { + public string Name; + public string[] Values; + public double Weight; + + public override string ToString() + { + return $"COMPlus_{Name}=[{string.Join(",", Values)}]"; + } + + public override bool Equals(object obj) + { + if (obj is not ComplusEnvVar otherObj) + { + return false; + } + + return otherObj.Name == Name; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + } + + public class ComplusEnvVarGroup + { + public string Name; + public double Weight; + public List Variables; + + /// + /// Weights of individual EnvVars present in this group. + /// + private readonly List> _variableWeights = new List>(); + + /// + /// Populate list of weighted choices. + /// + internal void PopulateWeights() + { + Variables.ForEach(v => AddVariable(v)); + } + + private void AddVariable(ComplusEnvVar variable) + { + _variableWeights.Add(new Weights(variable, variable.Weight)); + } + + public ComplusEnvVar GetRandomVariable() + { + return PRNG.WeightedChoice(_variableWeights); + } + + public override string ToString() + { + return $"{Name}: {Variables.Count}"; + } + } +} diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index bf9e9f0..d776409 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -29,13 +29,20 @@ public class RunOptions public List Configs; + public List BaselineEnvVars; + + public List TestEnvVars; + internal static RunOptions Initialize() { string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string antiGenConfig = Path.Combine(currentDirectory, "Config", "antigen.json"); Debug.Assert(File.Exists(antiGenConfig)); - return JsonConvert.DeserializeObject(File.ReadAllText(antiGenConfig)); + var runOption = JsonConvert.DeserializeObject(File.ReadAllText(antiGenConfig)); + EnvVarOptions.Initialize(runOption.BaselineEnvVars, runOption.TestEnvVars); + + return runOption; } } } diff --git a/Config/antigen.json b/Config/antigen.json new file mode 100644 index 0000000..e23c98b --- /dev/null +++ b/Config/antigen.json @@ -0,0 +1,708 @@ +{ + "Seed": -1, + "OutputDirectory": ".", + "NumTestCases": 10000, + "HoursToRun": 10, + "BaselineEnvVars": [ + { + "Name": "Default", + "Variables": [ + { + "Name": "JITMinOpts", + "Weight": 1.0, + "Values": [ + "1" + ] + }, + { + "Name": "TieredCompilation", + "Weight": 1.0, + "Values": [ + "1" + ] + } + ] + } + ], + "TestEnvVars": [ + { + "Name": "Default", + "Weight": 0, + "Variables": [ + { + "Name": "JitCloneLoops", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAlignLoops", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAlignLoopAdaptive", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAlignLoopMinBlockWeight", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "10", + "20" + ] + }, + { + "Name": "JitDoubleAlign", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableDevirtualization", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableLateDevirtualization", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitForceFallback", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JITInlineDepth", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "10", + "20" + ] + }, + { + "Name": "JitNoCMOV", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoCSE", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoCSE2", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoForceFallback", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoHoist", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoInline", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoMemoryBarriers", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoStructPromotion", + "Weight": 0.02, + "Values": [ + "0", + "1", + "2" + ] + }, + { + "Name": "JitNoUnroll", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitStackAllocToLocalSize", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "4", + "10", + "16", + "100" + ] + }, + { + "Name": "JitSkipArrayBoundCheck", + "Weight": 0.0002, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitSlowDebugChecksEnabled", + "Weight": 0.002, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitSplitFunctionSize", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "4", + "10", + "16", + "100" + ] + }, + { + "Name": "JitStackChecks", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "InjectFault", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoRngChks", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableNoWayAssert", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAggressiveInlining", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitMaxLocalsToTrack", + "Weight": 0.05, + "Values": [ + "0", + "0x10", + "0x400", + "0x800", + "0x1000" + ] + }, + { + "Name": "JitDoAssertionProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoCopyProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoEarlyProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoLoopHoisting", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoLoopInversion", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoRangeAnalysis", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoRedundantBranchOpts", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoSsa", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoValueNumber", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitOptRepeat", + "Weight": 0.0005, + "Values": [ + "*" + ] + }, + { + "Name": "JitOptRepeatCount", + "Weight": 0.0003, + "Values": [ + "1", + "2", + "5" + ] + }, + { + "Name": "TailCallLoopOpt", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "FastTailCalls", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableFinallyCloning", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableRemoveEmptyTry", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableGuardedDevirtualization", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitExpandCallsEarly", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + } + ] + }, + { + "Name": "JitStress", + "Weight": 0.3, + "Variables": [ + { + "Name": "JitStress", + "Weight": 0.04, + "Values": [ + "0", + "1", + "2" + ] + }, + { + "Name": "TailcallStress", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + } + ] + }, + { + "Name": "JitStressRegs", + "Weight": 0.3, + "Variables": [ + { + "Name": "JitStressRegs", + "Weight": 0.04, + "Values": [ + "0", + "1", + "2", + "3", + "4", + "8", + "0x10", + "0x80", + "0x1000" + ] + } + ] + }, + { + "Name": "GCStress", + "Weight": 0.3, + "Variables": [ + { + "Name": "GCStress", + "Weight": 0.04, + "Values": [ + "0x3", + "0xC", + "0xF" + ] + } + ] + }, + { + "Name": "Hardware", + "Weight": 0.2, + "Variables": [ + { + "Name": "EnableAES", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableAVX", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableAVX2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableBMI1", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableBMI2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableFMA", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableHWIntrinsic", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableIncompleteISAClass", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableLZCNT", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnablePCLMULQDQ", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnablePOPCNT", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE3", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE3_4", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE41", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE42", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSSE3", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "FeatureSIMD", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + } + ] + } + ], + "Configs": [ + { + "Name": "Basic", + "MaxStmtDepth": 2, + "MaxExprDepth": 3, + "MethodCount": 5, + "TryCatchFinallyStatementWeight": 0 + }, + { + "Name": "Structs", + "StructCount": 10, + "StructFieldCount": 10, + "NestedStructDepth": 5, + "NestedStructProbability": 0.4, + "StructFieldTypeProbability": 0.5, + "StructAliasProbability": 0.5, + "StructUsageProbability": 0.8 + }, + { + "Name": "MethodCalls", + "MethodCount": 100, + "MaxStatementCount": 3, + "MaxStmtDepth": 2, + "MaxExprDepth": 3, + "MethodCallStatementWeight": 0.7, + "MethodCallWeight": "0.4", + "ParamPassingRefProbability": 0.5, + "ParamPassingOutProbability": 0.4, + "LeafMethodsNoInlineProbability": 0.8, + "MaxMethodParametersCount": 20, + "StructUsageProbability": 0.7 + }, + { + "Name": "Full", + "MaxStmtDepth": 5, + "MaxExprDepth": 5, + "VariablesCount": 10, + "MethodCount": 5, + "MaxStatementCount": 10, + "TryCatchFinallyStatementWeight": 0.03, + "LocalVariablesLogProbability": 1.0 + }, + { + "Name": "ExceptionHandler", + "MaxStmtDepth": 5, + "MethodCount": 2, + "TryCatchFinallyStatementWeight": 0.5, + "CatchClausesCount": 5, + "FinallyClauseProbability": 0.7 + }, + { + "Name": "Loops", + "MaxStmtDepth": 5, + "MethodCount": 2, + "ForStatementWeight": 0.5, + "DoWhileStatementWeight": 0.5, + "WhileStatementWeight": 0.5, + "LoopParametersRemovalProbability": 0.4, + "LoopForwardProbability": 0.5, + "LoopStartFromInvariantProbabilty": 0.3, + "LoopStepPreBreakCondProbability": 0.6, + "UseLoopInvariantVariableProbability": 1.0, + "AllowLoopCondAtEnd": false + }, + { + "Name": "ControlFlow", + "MaxCaseCounts": 10, + "MaxStmtDepth": 6, + "MaxStatementCount": 4, + "IfElseStatementWeight": 0.4, + "ForStatementWeight": 0.5, + "DoWhileStatementWeight": 0.5, + "WhileStatementWeight": 0.5, + "SwitchStatementWeight": 0.45 + } + ] +} \ No newline at end of file diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 87976a2..8376fcd 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -55,7 +55,7 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) { string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{assemblyName}.exe"); - var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, Switches.CompileOptions); + var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, EnvVarOptions.CompileOptions); using (var ms = new MemoryStream()) { diff --git a/Program.cs b/Program.cs index 6394e7b..b1fa975 100644 --- a/Program.cs +++ b/Program.cs @@ -31,7 +31,6 @@ static void Main(string[] args) try { PRNG.Initialize(s_runOptions.Seed); - Switches.Initialize(); s_runOptions.CoreRun = args[0]; // trimmer diff --git a/Switches.cs b/Switches.cs deleted file mode 100644 index c6a9806..0000000 --- a/Switches.cs +++ /dev/null @@ -1,279 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Antigen -{ - internal class ComplusEnvVarGroup - { - public string Name { get; } - public List EnvVariables { get; } - - /// - /// Weights of individual EnvVars present in this group. - /// - private readonly List> variableWeights; - - public ComplusEnvVarGroup(string name) - { - Name = name; - EnvVariables = new List(); - variableWeights = new List>(); - } - - public void AddVariable(ComplusEnvVar variable) - { - EnvVariables.Add(variable); - variableWeights.Add(new Weights(variable, variable.Weight)); - } - - public ComplusEnvVar GetRandomVariable() - { - return PRNG.WeightedChoice(variableWeights); - } - - public ComplusEnvVar GetVariable(string name) - { - return EnvVariables.First(envVar => envVar.Name == name); - } - } - - internal class ComplusEnvVar - { - public string Name { get; } - public string[] Values { get; } - public double Weight { get; } - - public ComplusEnvVar(string name, string[] values, double weight) - { - Name = name; - Values = values; - Weight = weight; - } - - public override string ToString() - { - return $"COMPlus_{Name}=[{string.Join(",", Values)}]"; - } - - public override bool Equals(object obj) - { - if (obj is not ComplusEnvVar otherObj) - { - return false; - } - - return otherObj.Name == Name; - } - - public override int GetHashCode() - { - return Name.GetHashCode(); - } - } - - public class Switches - { - - private static ComplusEnvVarGroup s_baselineGroup; - private static ComplusEnvVarGroup s_defaultGroup; - private static ComplusEnvVarGroup s_jitStressGroup; - private static ComplusEnvVarGroup s_jitStressRegsGroup; - private static ComplusEnvVarGroup s_gcStressGroup; - private static ComplusEnvVarGroup s_hardwareGroup; - private static ComplusEnvVarGroup s_commonVarGroup; - - private static readonly string[] s_onOffSwitch = new string[] { "0", "1" }; - - public static void Initialize() - { - // Populate Baseline - s_baselineGroup = new ComplusEnvVarGroup("Baseline"); - s_baselineGroup.AddVariable(new ComplusEnvVar("JITMinOpts", new string[] { "1" }, 1.0)); - s_baselineGroup.AddVariable(new ComplusEnvVar("TieredCompilation", new string[] { "1" }, 1.0)); - - // Populate Common - s_commonVarGroup = new ComplusEnvVarGroup("Common"); - s_commonVarGroup.AddVariable(new ComplusEnvVar("JITMinOpts", new string[] { "0" }, 1.0)); - s_commonVarGroup.AddVariable(new ComplusEnvVar("TieredCompilation", new string[] { "0" }, 1.0)); - - // Default group - s_defaultGroup = new ComplusEnvVarGroup("Default"); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitCloneLoops", s_onOffSwitch, 0.04)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoops", s_onOffSwitch, 0.02)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoopAdaptive", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitAlignLoopMinBlockWeight", new string[] { "0", "1", "2", "10", "20" }, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoubleAlign", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableDevirtualization", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableLateDevirtualization", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitForceFallback", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JITInlineDepth", new string[] { "0", "1", "2", "10", "20" }, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCMOV", s_onOffSwitch, 0.04)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCSE", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoCSE2", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoForceFallback", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoHoist", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoInline", s_onOffSwitch, 0.04)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoMemoryBarriers", s_onOffSwitch, 0.02)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoStructPromotion", new string[] { "0", "1", "2" }, 0.02)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoUnroll", s_onOffSwitch, 0.02)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackAllocToLocalSize", new string[] { "0", "1", "2", "4", "10", "16", "100"}, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitSkipArrayBoundCheck", s_onOffSwitch, 0.0002)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitSlowDebugChecksEnabled", s_onOffSwitch, 0.02)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitSplitFunctionSize", new string[] { "0", "1", "2", "4", "10", "16", "100" }, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitStackChecks", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("InjectFault", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitNoRngChks", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableNoWayAssert", s_onOffSwitch, 0.01)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitAggressiveInlining", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitMaxLocalsToTrack", new string[] { "0", "0x10", "0x400", "0x800", "0x1000"}, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoAssertionProp", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoCopyProp", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoEarlyProp", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoLoopHoisting", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoLoopInversion", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoRangeAnalysis", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoRedundantBranchOpts", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoSsa", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitDoValueNumber", s_onOffSwitch, 0.05)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeat", new string[] { "*" }, 0.0005)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitOptRepeatCount", new string[] { "1", "2", "5" }, 0.0003)); - s_defaultGroup.AddVariable(new ComplusEnvVar("TailCallLoopOpt", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("FastTailCalls", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableFinallyCloning", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableRemoveEmptyTry", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitEnableGuardedDevirtualization", s_onOffSwitch, 0.03)); - s_defaultGroup.AddVariable(new ComplusEnvVar("JitExpandCallsEarly", s_onOffSwitch, 0.03)); - - // JitStress - s_jitStressGroup = new ComplusEnvVarGroup("JitStress"); - s_jitStressGroup.AddVariable(new ComplusEnvVar("JitStress", new string[] { "0", "1", "2" }, 0.04)); - s_jitStressGroup.AddVariable(new ComplusEnvVar("TailcallStress", s_onOffSwitch, 0.02)); - - // JitStressRegs - s_jitStressRegsGroup = new ComplusEnvVarGroup("JitStressRegs"); - s_jitStressRegsGroup.AddVariable(new ComplusEnvVar("JitStressRegs", new string[] { "0", "1", "2", "3", "4", "8", "0x10", "0x80", "0x1000" }, 0.04)); - - // GCStress - s_gcStressGroup = new ComplusEnvVarGroup("GCStress"); - s_gcStressGroup.AddVariable(new ComplusEnvVar("GCStress", new string[] { "0x3", "0xC", "0xF" }, 0.04)); - - // Hardware - s_hardwareGroup = new ComplusEnvVarGroup("Hardware"); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAES", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAVX", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableAVX2", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableBMI1", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableBMI2", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableFMA", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableHWIntrinsic", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableIncompleteISAClass", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableLZCNT", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnablePCLMULQDQ", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnablePOPCNT", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE2", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE3", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE3_4", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE41", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSE42", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("EnableSSSE3", s_onOffSwitch, 0.02)); - s_hardwareGroup.AddVariable(new ComplusEnvVar("FeatureSIMD", s_onOffSwitch, 0.02)); - } - - /// - /// Returns baseline variables - /// - /// - public static Dictionary BaseLineVars() - { - var envVars = new Dictionary(); - foreach (var variable in s_baselineGroup.EnvVariables) - { - envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; - } - return envVars; - } - - /// - /// Returns test variables - /// - /// - public static Dictionary TestVars() - { - var envVars = new Dictionary(); - - // common variables - foreach (var variable in s_commonVarGroup.EnvVariables) - { - envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; - } - - // default variables - var usedEnvVars = new HashSet(); - //TODO: config no. of variables to pick - var defaultVariablesCount = PRNG.Next(1, 8); - for (var i = 0; i < defaultVariablesCount; i++) - { - ComplusEnvVar envVar; - - // Avoid duplicate variables - do - { - envVar = s_defaultGroup.GetRandomVariable(); - } while (!usedEnvVars.Add(envVar.Name)); - - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; - } - - - // 30% of time add JitStress flag - if (PRNG.Decide(0.3)) - { - var envVar = s_jitStressGroup.GetRandomVariable(); - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; - } - - // 30% of time add JitStressRegs flag - if (PRNG.Decide(0.3)) - { - var envVar = s_jitStressRegsGroup.GetRandomVariable(); - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; - } - - // 20% of time add Hardware flag - if (PRNG.Decide(0.2)) - { - usedEnvVars = new HashSet(); - //TODO: config no. of variables to pick - var hardwareVariablesCount = PRNG.Next(1, 5); - for (var i = 0; i < hardwareVariablesCount; i++) - { - ComplusEnvVar envVar; - - // Avoid duplicate variables - do - { - envVar = s_hardwareGroup.GetRandomVariable(); - } while (!usedEnvVars.Add(envVar.Name)); - - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; - } - } - - // 30% of time add GCStress - if (PRNG.Decide(0.3)) - { - var envVar = s_gcStressGroup.GetRandomVariable(); - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; - } - - return envVars; - } - - internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); - } - -} diff --git a/TestCase.cs b/TestCase.cs index 95f65e2..6eb3e7e 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -134,8 +134,8 @@ public TestResult Verify() } #endif - var baselineVariables = Switches.BaseLineVars(); - var testVariables = Switches.TestVars(); + var baselineVariables = EnvVarOptions.BaseLineVars(); + var testVariables = EnvVarOptions.TestVars(); // Execute test first and see if we have any errors/asserts string test = s_testRunner.Execute(compileResult, testVariables, 30); From bd2ed7ce352d4233b3c003572d04caebc5dd018e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 22 Aug 2021 23:43:38 -0700 Subject: [PATCH 058/149] Trimmer: Just save lkg --- Trimmer/TestTrimmer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index f47c9ea..99482ef 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -77,7 +77,7 @@ private void ParseEnvironment() public void Trim() { var trimTask = Task.Run(TrimTree); - trimTask.Wait(TimeSpan.FromMinutes(20)); + trimTask.Wait(TimeSpan.FromMinutes(40)); } /// @@ -188,12 +188,15 @@ public bool TrimEnvVars() string value = _testVariables[envVar]; _testVariables.Remove(envVar); + Console.Write($"{s_iterId}. Removing {envVar}={value}"); if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) == TestResult.Pass) { + Console.WriteLine(" - Success"); _testVariables[envVar] = value; } else { + Console.WriteLine(" - Revert"); trimmedAtleastOne = true; } } @@ -369,7 +372,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); //} - string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, Switches.BaseLineVars(), 10); + string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, EnvVarOptions.BaseLineVars(), 10); string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 10); TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; @@ -449,7 +452,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< //TODO: Only if something was visited - string failedFileName = $"{iterId}-lkg"; + string failedFileName = "repro-lkg"; string failFile = Path.Combine(Path.GetDirectoryName(_testFileToTrim), $"{ failedFileName}.g.cs"); //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); From fd50b69c624810e8aab5da1df6f6ca12c17ac44f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 23 Aug 2021 17:21:46 -0700 Subject: [PATCH 059/149] Add Log() method as generation --- Helpers/Expressions.cs | 22 ++++++++++++++++++++++ Helpers/TestRunner.cs | 2 +- Helpers/VariableDeclarationHelper.cs | 6 +++--- Program.cs | 7 +++++-- TestCase.cs | 26 +++++++++++++------------- TestClass.cs | 8 ++++---- TestMethod.cs | 18 +++++++++--------- Tree/AstUtils.cs | 2 -- Tree/Types.cs | 6 ++++-- 9 files changed, 61 insertions(+), 36 deletions(-) diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index e92f974..811761b 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -63,5 +63,27 @@ public static SyntaxList ToSyntaxList(this IList list) where T : Syntax { return new SyntaxList(list); } + + /// + /// Generate log invoke statement + /// + /// + /// + public static StatementSyntax GetLogInvokeStatement(string variableName) + { + return ExpressionStatement( + InvocationExpression( + IdentifierName("Log")) + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName))), + Token(SyntaxKind.CommaToken), + Argument(GetVariableAccessExpression(variableName)) + } + )))); + } } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 8376fcd..e6623b3 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -181,7 +181,7 @@ internal string Execute(CompileResult compileResult, Dictionary catch { } return "TIMEOUT"; } - return output.ToString(); + return output.ToString().Trim(); } } } diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs index a3fce93..f1314c5 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Helpers/VariableDeclarationHelper.cs @@ -37,7 +37,7 @@ public static VariableDeclarationSyntax GetVariableDeclaration(Tree.ValueType va private static VariableDeclarationSyntax GetVariableDeclaration(string variableType, string variableName) { TypeSyntax variableTypeSyntax; - if (variableType.Contains(".")) + if (variableType.Contains('.')) { string[] seperatedTypes = variableType.Split('.', StringSplitOptions.RemoveEmptyEntries); NameSyntax nameSyntax = QualifiedName( @@ -71,7 +71,7 @@ public static PredefinedTypeSyntax GetToken(SyntaxKind syntaxKind) public static ExpressionSyntax GetVariableAccessExpression(string variableName) { - if (variableName.Contains(".")) + if (variableName.Contains('.')) { string[] seperatedFields = variableName.Split('.', StringSplitOptions.RemoveEmptyEntries); var memberAccessExpr = MemberAccessExpression( @@ -98,7 +98,7 @@ public static ObjectCreationExpressionSyntax GetObjectCreationExpression(string { TypeSyntax objectTypeSyntax; - if (objectType.Contains(".")) + if (objectType.Contains('.')) { string[] seperatedTypes = objectType.Split('.', StringSplitOptions.RemoveEmptyEntries); NameSyntax nameSyntax = QualifiedName( diff --git a/Program.cs b/Program.cs index b1fa975..0a3241f 100644 --- a/Program.cs +++ b/Program.cs @@ -42,7 +42,7 @@ static void Main(string[] args) return; } - Parallel.For(0, 1, (p) => RunTest()); + Parallel.For(0, 4, (p) => RunTest()); } catch (OutOfMemoryException oom) @@ -107,7 +107,8 @@ static void RunTest() TestCase testCase = new TestCase(currTestId, s_runOptions); testCase.Generate(); TestResult result = testCase.Verify(); - Console.WriteLine($"Test# {currTestId} [{testCase.Config.Name}] - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); + //Console.WriteLine($"Test# {currTestId} [{testCase.Config.Name}] - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); + Console.WriteLine("Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", currTestId, testCase.Config.Name, Enum.GetName(typeof(TestResult), result), (double)Process.GetCurrentProcess().WorkingSet64 / 1000000); localStats[result]++; if (localStats.Count == 10) @@ -115,6 +116,8 @@ static void RunTest() SaveResult(localStats); localStats.Clear(); } + + GC.Collect(); } } } diff --git a/TestCase.cs b/TestCase.cs index 6eb3e7e..0a0ad28 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -110,19 +110,19 @@ public TestResult Verify() StringBuilder fileContents; if (compileResult.AssemblyFullPath == null) { - fileContents = new StringBuilder(); - - fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); - fileContents.AppendLine("/*"); - fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); - foreach (var error in compileResult.CompileErrors) - { - fileContents.AppendLine(error.ToString()); - } - fileContents.AppendLine("*/"); - - string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); - File.WriteAllText(errorFile, fileContents.ToString()); + //fileContents = new StringBuilder(); + + //fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); + //fileContents.AppendLine("/*"); + //fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); + //foreach (var error in compileResult.CompileErrors) + //{ + // fileContents.AppendLine(error.ToString()); + //} + //fileContents.AppendLine("*/"); + + //string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); + //File.WriteAllText(errorFile, fileContents.ToString()); return TestResult.CompileError; } diff --git a/TestClass.cs b/TestClass.cs index c7f532a..a90b0ca 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -50,12 +50,12 @@ public void RegisterMethod(MethodSignature methodSignature) /// /// Returns all non-leaf methods /// - public List AllNonLeafMethods => _methods.Where(m => !m.Data.IsLeaf).Select(m => m.Data).ToList(); + public IEnumerable> AllNonLeafMethods => _methods.Where(m => !m.Data.IsLeaf); /// /// Returns all leaf methods /// - public List AllLeafMethods => _methods.Where(m => m.Data.IsLeaf).Select(m => m.Data).ToList(); + public IEnumerable> AllLeafMethods => _methods.Where(m => m.Data.IsLeaf); /// /// Get random method that returns specfic returnType. Null if no such @@ -79,8 +79,8 @@ public MethodSignature GetRandomMethod(Tree.ValueType returnType) /// public MethodSignature GetRandomLeafMethod(Tree.ValueType returnType) { - var matchingMethods = _methods.Where(m => m.Data.IsLeaf).Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); - if (matchingMethods.Count == 0) + var matchingMethods = AllLeafMethods.Where(m => m.Data.ReturnType.Equals(returnType)); + if (matchingMethods.Count() == 0) { return null; } diff --git a/TestMethod.cs b/TestMethod.cs index 9e61cad..7590cf7 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -66,7 +66,7 @@ protected Scope PopScope(Action trackLocalVariables) internal static void LogVariable(IList stmtList, string variableName) { - stmtList.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); + stmtList.Add(Helpers.GetLogInvokeStatement(variableName)); } /// @@ -188,8 +188,8 @@ public virtual MethodDeclarationSyntax Generate() //TODO-future: Select any assignOper //Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.ReturnType, 0); - ExpressionSyntax rhs = MethodCallHelper(nonLeafMethod, 0); + ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.Data.ReturnType, 0); + ExpressionSyntax rhs = MethodCallHelper(nonLeafMethod.Data, 0); methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign", 0)); } @@ -197,14 +197,14 @@ public virtual MethodDeclarationSyntax Generate() // print all static variables foreach (var variableName in _testClass.ClassScope.AllVariables) { - methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); + methodBody.Add(Helpers.GetLogInvokeStatement(variableName)); } } // print all variables foreach (var variableName in CurrentScope.AllVariables) { - methodBody.Add(ParseStatement($"Log(\"{variableName}\", {variableName});")); + methodBody.Add(Helpers.GetLogInvokeStatement(variableName)); } // return statement @@ -565,11 +565,12 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(variableName => LogVariable(tryBody, variableName)); // pop 'try' body scope IList catchClauses = new List(); - var allExceptions = Tree.ValueType.AllExceptions; + var allExceptions = Tree.ValueType.AllExceptions.Select(x => x.Key).ToList(); var caughtExceptions = new List(); + for (int catchId = 0; catchId < catchCounts; catchId++) { - var exceptionToCatch = allExceptions[PRNG.Next(allExceptions.Count)]; + var exceptionToCatch = allExceptions[PRNG.Next(allExceptions.Count())]; allExceptions.Remove(exceptionToCatch); // If we already generated a catch-clause of superclass, skip remaining catch clauses. @@ -600,7 +601,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(catchBody, variableName)); // pop 'catch' body scope - catchClauses.Add(CatchClause(CatchDeclaration(IdentifierName(exceptionToCatch.Name)), null, Block(catchBody))); + catchClauses.Add(CatchClause(Tree.ValueType.AllExceptions[exceptionToCatch], null, Block(catchBody))); } IList finallyBody = new List(); @@ -1087,7 +1088,6 @@ public override string ToString() var paramList = Parameters.Select(p => $"{(p.PassingWay == ParamValuePassing.None ? "" : Enum.GetName(typeof(ParamValuePassing), p.PassingWay))} {p.ParamType}"); return $"{ReturnType} {MethodName}({string.Join(", ", paramList)})"; } - } public class MethodParam diff --git a/Tree/AstUtils.cs b/Tree/AstUtils.cs index 2c87c22..83ea6df 100644 --- a/Tree/AstUtils.cs +++ b/Tree/AstUtils.cs @@ -14,10 +14,8 @@ public class AstUtils private List> AllStructExpressions = new List>(); private List> AllStatements = new List>(); private List> AllTypes = new List>(); - private List> AllStatementsWithCFStmts = new List>(); private List> AllTerminalExpressions = new List>(); private List> AllTerminalStatements = new List>(); - private List> AllTerminalStatementsWithCFStmts = new List>(); private List> AllOperators = new List>(); private ConfigOptions ConfigOptions; diff --git a/Tree/Types.cs b/Tree/Types.cs index ef56a25..98df511 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -1,9 +1,11 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Tree { @@ -226,11 +228,11 @@ public string VariableNameHint() } } - public static List AllExceptions => + public static IDictionary AllExceptions => typeof(Exception).Assembly.GetTypes() .Where(x => x.IsSubclassOf(typeof(Exception))) .Where(n => n.FullName.StartsWith("System.") && n.FullName.LastIndexOf(".") == 6) - .ToList(); + .ToDictionary(t => t, t => CatchDeclaration(IdentifierName(t.Name))); public override string ToString() { From 41ae1ec82cf2f97f23ef1ffb4cfef894f96d07c1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 24 Aug 2021 11:27:36 -0700 Subject: [PATCH 060/149] TreatWarningsAsError=false --- Antigen.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Antigen.csproj b/Antigen.csproj index 4ab89e9..afd3f05 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -17,6 +17,10 @@ + + false + + PreserveNewest From 24d811d0c63075810aa8c970fd2ab6cf161472c8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 24 Aug 2021 12:09:22 -0700 Subject: [PATCH 061/149] Pass OutputDirectory as command line, done --- Config/antigen.json | 2 +- Program.cs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Config/antigen.json b/Config/antigen.json index e23c98b..1ecc841 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,7 +1,7 @@ { "Seed": -1, "OutputDirectory": ".", - "NumTestCases": 10000, + "NumTestCases": 1000, "HoursToRun": 10, "BaselineEnvVars": [ { diff --git a/Program.cs b/Program.cs index 0a3241f..b6bd1b1 100644 --- a/Program.cs +++ b/Program.cs @@ -25,6 +25,7 @@ class Program }; private static int s_testId = 0; + private static bool done = false; static void Main(string[] args) { @@ -32,15 +33,16 @@ static void Main(string[] args) { PRNG.Initialize(s_runOptions.Seed); s_runOptions.CoreRun = args[0]; + s_runOptions.OutputDirectory = args[1]; - // trimmer - if (args.Length > 1) - { - string testCaseToTrim = args[1]; - TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, s_runOptions); - testTrimmer.Trim(); - return; - } + //// trimmer + //if (args.Length > 1) + //{ + // string testCaseToTrim = args[1]; + // TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, s_runOptions); + // testTrimmer.Trim(); + // return; + //} Parallel.For(0, 4, (p) => RunTest()); @@ -64,6 +66,10 @@ private static int GetNextTestId() { lock (s_spinLock) { + if (s_testId >= s_runOptions.NumTestCases) + { + done = true; + } return ++s_testId; } } @@ -101,7 +107,7 @@ static void RunTest() { TestResult.OOM, 0 }, }; - while (true) + while (!done) { int currTestId = GetNextTestId(); TestCase testCase = new TestCase(currTestId, s_runOptions); From f75ef68902568769f45cea1c97c2207167bb48f9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 26 Aug 2021 12:33:54 -0700 Subject: [PATCH 062/149] Reduce further memory --- Helpers/Expressions.cs | 3 ++- Helpers/TestRunner.cs | 56 +++++++++++++++++++++++++----------------- Program.cs | 30 +++++++++++++++++----- TestCase.cs | 51 +++++++++++++++++++++++--------------- 4 files changed, 90 insertions(+), 50 deletions(-) diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index 811761b..a04c55b 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -79,7 +79,8 @@ public static StatementSyntax GetLogInvokeStatement(string variableName) SeparatedList( new SyntaxNodeOrToken[] { - Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName))), + // For variable names, just take 10 characters for longer variable names + Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName.Substring(0, Math.Min(variableName.Length, 10))))), Token(SyntaxKind.CommaToken), Argument(GetVariableAccessExpression(variableName)) } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index e6623b3..4ce79b0 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -67,16 +67,22 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) catch (Exception ex) { Console.WriteLine(ex.Message); - return new CompileResult(ex, ImmutableArray.Empty, null, null); + return new CompileResult(ex); } if (!result.Success) - return new CompileResult(null, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToImmutableArray(), null, null); + { +#if DEBUG + return new CompileResult(result.Diagnostics); +#else + return new CompileResult(null, null); +#endif + } ms.Seek(0, SeekOrigin.Begin); File.WriteAllBytes(assemblyFullPath, ms.ToArray()); - return new CompileResult(null, ImmutableArray.Empty, assemblyName, assemblyFullPath); + return new CompileResult(assemblyName, assemblyFullPath); } } @@ -181,7 +187,16 @@ internal string Execute(CompileResult compileResult, Dictionary catch { } return "TIMEOUT"; } - return output.ToString().Trim(); + + string finalOutput = ""; + try + { + finalOutput = output.ToString(); + + } catch (ArgumentOutOfRangeException) + { + } + return finalOutput.Trim(); } } } @@ -189,32 +204,27 @@ internal string Execute(CompileResult compileResult, Dictionary internal class CompileResult { - public CompileResult(Exception roslynException, ImmutableArray diagnostics, string assemblyName, string assemblyFullPath) + public CompileResult(IEnumerable diagnostics) + { + CompileErrors = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Error); + CompileWarnings = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Warning); + } + + public CompileResult(string assemblyName, string assemblyFullPath) { - RoslynException = roslynException; - List errors = new List(); - List warnings = new List(); - foreach (var diag in diagnostics) - { - if (diag.Severity == DiagnosticSeverity.Error) - { - errors.Add(diag); - } - else if (diag.Severity == DiagnosticSeverity.Warning) - { - errors.Add(diag); - } - } - CompileErrors = errors.ToImmutableArray(); - CompileWarnings = warnings.ToImmutableArray(); AssemblyName = assemblyName; AssemblyFullPath = assemblyFullPath; } + public CompileResult(Exception roslynException) + { + RoslynException = roslynException; + } + public string AssemblyName { get; } public Exception RoslynException { get; } - public ImmutableArray CompileErrors { get; } - public ImmutableArray CompileWarnings { get; } + public IEnumerable CompileErrors { get; } + public IEnumerable CompileWarnings { get; } public string AssemblyFullPath { get; } } } diff --git a/Program.cs b/Program.cs index b6bd1b1..9118074 100644 --- a/Program.cs +++ b/Program.cs @@ -16,16 +16,18 @@ class Program private static readonly RunOptions s_runOptions = RunOptions.Initialize(); private static readonly Dictionary s_stats = new Dictionary() { + { TestResult.RoslynException, 0 }, { TestResult.CompileError, 0 }, { TestResult.Assertion, 0 }, { TestResult.KnownErrors, 0 }, - {TestResult.OutputMismatch, 0 }, - {TestResult.Pass, 0 }, - {TestResult.OOM, 0 }, + { TestResult.OutputMismatch, 0 }, + { TestResult.Pass, 0 }, + { TestResult.OOM, 0 }, }; private static int s_testId = 0; private static bool done = false; + private static readonly DateTime s_StartTime = DateTime.Now; static void Main(string[] args) { @@ -35,6 +37,16 @@ static void Main(string[] args) s_runOptions.CoreRun = args[0]; s_runOptions.OutputDirectory = args[1]; + if (!File.Exists(s_runOptions.CoreRun)) + { + throw new Exception($"{s_runOptions.CoreRun} doesn't exist"); + } + if (!Directory.Exists(s_runOptions.OutputDirectory)) + { + Console.WriteLine($"Creating {s_runOptions.OutputDirectory}"); + Directory.CreateDirectory(s_runOptions.OutputDirectory); + } + //// trimmer //if (args.Length > 1) //{ @@ -44,7 +56,7 @@ static void Main(string[] args) // return; //} - Parallel.For(0, 4, (p) => RunTest()); + Parallel.For(0, 1, (p) => RunTest()); } catch (OutOfMemoryException oom) @@ -99,6 +111,7 @@ static void RunTest() { Dictionary localStats = new Dictionary() { + { TestResult.RoslynException, 0 }, { TestResult.CompileError, 0 }, { TestResult.Assertion, 0 }, { TestResult.KnownErrors, 0 }, @@ -113,8 +126,13 @@ static void RunTest() TestCase testCase = new TestCase(currTestId, s_runOptions); testCase.Generate(); TestResult result = testCase.Verify(); - //Console.WriteLine($"Test# {currTestId} [{testCase.Config.Name}] - {Enum.GetName(typeof(TestResult), result)}. {(double)Process.GetCurrentProcess().WorkingSet64 / 1000000} MB "); - Console.WriteLine("Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", currTestId, testCase.Config.Name, Enum.GetName(typeof(TestResult), result), (double)Process.GetCurrentProcess().WorkingSet64 / 1000000); + Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", + currTestId, + testCase.Config.Name, + Enum.GetName(typeof(TestResult), result), + (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, + (DateTime.Now - s_StartTime).ToString()); + localStats[result]++; if (localStats.Count == 10) diff --git a/TestCase.cs b/TestCase.cs index 0a0ad28..529ba19 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -22,6 +22,7 @@ namespace Antigen { public enum TestResult { + RoslynException, CompileError, KnownErrors, OutputMismatch, @@ -107,10 +108,9 @@ public TestResult Verify() SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; // RslnUtilities.GetValidSyntaxTree(testCaseRoot); CompileResult compileResult = s_testRunner.Compile(syntaxTree, Name); - StringBuilder fileContents; if (compileResult.AssemblyFullPath == null) { - //fileContents = new StringBuilder(); + // StringBuilder fileContents = new StringBuilder(); //fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); //fileContents.AppendLine("/*"); @@ -123,8 +123,7 @@ public TestResult Verify() //string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); //File.WriteAllText(errorFile, fileContents.ToString()); - - return TestResult.CompileError; + return compileResult.RoslynException != null ? TestResult.RoslynException : TestResult.CompileError; } #if UNREACHABLE else @@ -145,15 +144,16 @@ public TestResult Verify() if (test.Contains("Out of memory")) { #if UNREACHABLE - SaveTestCase(testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-oom"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-oom"); + #endif - return TestResult.OOM; + return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); } // If test assertion else if (!string.IsNullOrEmpty(testAssertion)) { SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); - return TestResult.Assertion; + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); } else { @@ -170,10 +170,10 @@ public TestResult Verify() // ignore errors } #if UNREACHABLE - SaveTestCase(testCaseRoot, null, null, test, testVariables, knownError, $"{Name}-knownerrors"); -#endif + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-knownerrors"); - return TestResult.KnownErrors; +#endif + return TheTestResult(compileResult.AssemblyFullPath, TestResult.KnownErrors); } } } @@ -185,33 +185,38 @@ public TestResult Verify() if (baseline.Contains("Out of memory")) { #if UNREACHABLE - SaveTestCase(testCaseRoot, baseline, baselineVariables, null, null, "Out of memory", $"{Name}-base-oom"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, "Out of memory", $"{Name}-base-oom"); ; #endif - return TestResult.OOM; + return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); } // Is there assertion in baseline? else if (!string.IsNullOrEmpty(baselineAssertion)) { SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); - return TestResult.Assertion; + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); } // If baseline and test output doesn't match else if (baseline != test) { SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{ Name}-output-mismatch"); - return TestResult.OutputMismatch; + return TheTestResult(compileResult.AssemblyFullPath, TestResult.OutputMismatch); } + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + } + + private TestResult TheTestResult(string assemblyPath, TestResult result) + { try { - File.Delete(compileResult.AssemblyFullPath); + File.Delete(assemblyPath); } catch (Exception) { // ignore errors } - return TestResult.Pass; + return result; } private void SaveTestCase( @@ -252,7 +257,10 @@ private void SaveTestCase( { fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); } - fileContents.AppendLine($"// TestVars: {string.Join("|", testVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + if (testVars != null) + { + fileContents.AppendLine($"// TestVars: {string.Join("|", testVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + } fileContents.AppendLine("//"); fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); fileContents.AppendLine("/*"); @@ -276,10 +284,13 @@ private void SaveTestCase( fileContents.AppendLine(); fileContents.AppendLine("Environment:"); fileContents.AppendLine(); - foreach (var envVars in testVars) + if (testVars != null) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); -} + foreach (var envVars in testVars) + { + fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + } + } fileContents.AppendLine(); fileContents.AppendLine(testOutput); fileContents.AppendLine("*/"); From ce48954b47d5b0eca5e493baa746049566f9acd1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 6 Sep 2021 23:41:20 -0700 Subject: [PATCH 063/149] Merge Kinds --- Tree/Expressions.cs | 15 --------------- Tree/Kinds.cs | 35 +++++++++++++++++++++++++++++++++++ Tree/Statements.cs | 20 -------------------- 3 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 Tree/Expressions.cs create mode 100644 Tree/Kinds.cs delete mode 100644 Tree/Statements.cs diff --git a/Tree/Expressions.cs b/Tree/Expressions.cs deleted file mode 100644 index a7959c0..0000000 --- a/Tree/Expressions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Antigen.Tree -{ - public enum ExprKind - { - LiteralExpression, - VariableExpression, - BinaryOpExpression, - AssignExpression, - MethodCallExpression, - } - - //public struct Expression - //{ - //} -} diff --git a/Tree/Kinds.cs b/Tree/Kinds.cs new file mode 100644 index 0000000..78f1e49 --- /dev/null +++ b/Tree/Kinds.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Tree +{ + public enum ExprKind + { + LiteralExpression, + VariableExpression, + BinaryOpExpression, + AssignExpression, + MethodCallExpression, + } + + public enum StmtKind + { + VariableDeclaration, + IfElseStatement, + AssignStatement, + ForStatement, + DoWhileStatement, + WhileStatement, + ReturnStatement, + TryCatchFinallyStatement, + SwitchStatement, + MethodCallStatement, + } +} diff --git a/Tree/Statements.cs b/Tree/Statements.cs deleted file mode 100644 index a844669..0000000 --- a/Tree/Statements.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Antigen.Tree -{ - public enum StmtKind - { - VariableDeclaration, - IfElseStatement, - AssignStatement, - ForStatement, - DoWhileStatement, - WhileStatement, - ReturnStatement, - TryCatchFinallyStatement, - SwitchStatement, - MethodCallStatement, - } - - //public class Statements - //{ - //} -} From 1a2d37f302877950ea5393126dbbe40b43ade480 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 6 Sep 2021 23:45:47 -0700 Subject: [PATCH 064/149] Cache some of the roslyn trees --- Helpers/Expressions.cs | 23 ----------------------- Helpers/PreGenerated.cs | 2 ++ Helpers/TestRunner.cs | 1 + Program.cs | 5 +++-- Statements/ForStatement.cs | 4 ++-- Statements/LoopStatement.cs | 2 +- TestCase.cs | 19 +++++++++++++++++++ TestMethod.cs | 37 ++++++++++++++++++++++++++++++------- Tree/Scope.cs | 2 +- 9 files changed, 59 insertions(+), 36 deletions(-) diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs index a04c55b..e92f974 100644 --- a/Helpers/Expressions.cs +++ b/Helpers/Expressions.cs @@ -63,28 +63,5 @@ public static SyntaxList ToSyntaxList(this IList list) where T : Syntax { return new SyntaxList(list); } - - /// - /// Generate log invoke statement - /// - /// - /// - public static StatementSyntax GetLogInvokeStatement(string variableName) - { - return ExpressionStatement( - InvocationExpression( - IdentifierName("Log")) - .WithArgumentList( - ArgumentList( - SeparatedList( - new SyntaxNodeOrToken[] - { - // For variable names, just take 10 characters for longer variable names - Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName.Substring(0, Math.Min(variableName.Length, 10))))), - Token(SyntaxKind.CommaToken), - Argument(GetVariableAccessExpression(variableName)) - } - )))); - } } } diff --git a/Helpers/PreGenerated.cs b/Helpers/PreGenerated.cs index d3a5b43..25ebe85 100644 --- a/Helpers/PreGenerated.cs +++ b/Helpers/PreGenerated.cs @@ -101,5 +101,7 @@ public static MemberDeclarationSyntax LoggerVariableDecl return loggerVarDecl; } } + + public static InvocationExpressionSyntax LogInvocationExpression = SyntaxFactory.InvocationExpression(IdentifierName("Log")); } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 4ce79b0..926f398 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -81,6 +81,7 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) ms.Seek(0, SeekOrigin.Begin); File.WriteAllBytes(assemblyFullPath, ms.ToArray()); + Console.WriteLine($"{ms.Length} bytes"); return new CompileResult(assemblyName, assemblyFullPath); } diff --git a/Program.cs b/Program.cs index 9118074..e830a14 100644 --- a/Program.cs +++ b/Program.cs @@ -35,12 +35,13 @@ static void Main(string[] args) { PRNG.Initialize(s_runOptions.Seed); s_runOptions.CoreRun = args[0]; - s_runOptions.OutputDirectory = args[1]; if (!File.Exists(s_runOptions.CoreRun)) { throw new Exception($"{s_runOptions.CoreRun} doesn't exist"); } + + s_runOptions.OutputDirectory = args[1]; if (!Directory.Exists(s_runOptions.OutputDirectory)) { Console.WriteLine($"Creating {s_runOptions.OutputDirectory}"); @@ -56,7 +57,7 @@ static void Main(string[] args) // return; //} - Parallel.For(0, 1, (p) => RunTest()); + Parallel.For(0, 4, (p) => RunTest()); } catch (OutOfMemoryException oom) diff --git a/Statements/ForStatement.cs b/Statements/ForStatement.cs index c735777..c3d3657 100644 --- a/Statements/ForStatement.cs +++ b/Statements/ForStatement.cs @@ -47,7 +47,7 @@ public override List Generate(bool labels) ExpressionSyntax condition = GenerateIVLoopGuardCode(); if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) { - ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, Helpers.GetVariableAccessExpression(LoopVar), Bounds); + ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, TestCase.GetExpressionSyntax(LoopVar), Bounds); if (condition == null) { condition = boundCond; @@ -62,7 +62,7 @@ public override List Generate(bool labels) SeparatedSyntaxList incrementors = GenerateIVStepCode(); if (LoopKind == Kind.NormalLoop) { - incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, Helpers.GetVariableAccessExpression(LoopVar))); + incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, TestCase.GetExpressionSyntax(LoopVar))); } else if (LoopKind == Kind.ComplexLoop) { diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 6d8075e..3aa3571 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -530,7 +530,7 @@ public void AddToBody(StatementSyntax stmt) public void LogVariable(string name) { - TestMethod.LogVariable(Body, name); + Body.Add(TestMethod.GetLogInvokeStatement(name)); } public LoopStatement(TestCase tc) diff --git a/TestCase.cs b/TestCase.cs index 529ba19..593d5f1 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.Specialized; @@ -71,6 +72,24 @@ public enum CompilationType new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), }; + private static readonly ConcurrentDictionary _variableExpressions = new(); + + public static ExpressionSyntax GetExpressionSyntax(string variableName) + { + // Cache max 1000 expressions after which recycle them. + if (_variableExpressions.Count > 1000) + { + _variableExpressions.Clear(); + } + + if (!_variableExpressions.TryGetValue(variableName, out var exprSyntax)) + { + exprSyntax = Helpers.GetVariableAccessExpression(variableName); + _variableExpressions[variableName] = exprSyntax; + } + + return exprSyntax; + } //private List classesList; //private List methodsList; diff --git a/TestMethod.cs b/TestMethod.cs index 7590cf7..81e7e0a 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -64,9 +64,9 @@ protected Scope PopScope(Action trackLocalVariables) return ret; } - internal static void LogVariable(IList stmtList, string variableName) + internal void LogVariable(IList stmtList, string variableName) { - stmtList.Add(Helpers.GetLogInvokeStatement(variableName)); + stmtList.Add(GetLogInvokeStatement(variableName)); } /// @@ -162,7 +162,7 @@ public virtual MethodDeclarationSyntax Generate() methodBody.Add(Annotate(LocalDeclarationStatement( Helpers.GetVariableDeclaration(structType, aliasVariableName, - Helpers.GetVariableAccessExpression(variableName))), "struct-alias-init", 0)); + TestCase.GetExpressionSyntax(variableName))), "struct-alias-init", 0)); } @@ -197,14 +197,14 @@ public virtual MethodDeclarationSyntax Generate() // print all static variables foreach (var variableName in _testClass.ClassScope.AllVariables) { - methodBody.Add(Helpers.GetLogInvokeStatement(variableName)); + methodBody.Add(GetLogInvokeStatement(variableName)); } } // print all variables foreach (var variableName in CurrentScope.AllVariables) { - methodBody.Add(Helpers.GetLogInvokeStatement(variableName)); + methodBody.Add(GetLogInvokeStatement(variableName)); } // return statement @@ -744,7 +744,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i case ExprKind.VariableExpression: { - return Annotate(Helpers.GetVariableAccessExpression(CurrentScope.GetRandomVariable(exprType)), "Var"); + return Annotate(TestCase.GetExpressionSyntax(CurrentScope.GetRandomVariable(exprType)), "Var"); } case ExprKind.BinaryOpExpression: @@ -864,7 +864,7 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i /// public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string variableName) { - ExpressionSyntax lhs = Annotate(Helpers.GetVariableAccessExpression(variableName), "specific-Var"); + ExpressionSyntax lhs = Annotate(TestCase.GetExpressionSyntax(variableName), "specific-Var"); ExpressionSyntax rhs; int noOfAttempts = TC.Config.NumOfAttemptsForExpression; @@ -1042,6 +1042,29 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment, int return statement; #endif } + + + /// + /// Generate log invoke statement + /// + /// + /// + public static StatementSyntax GetLogInvokeStatement(string variableName) + { + return ExpressionStatement( + PreGenerated.LogInvocationExpression + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + // For variable names, just take 10 characters for longer variable names + Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName.Substring(0, Math.Min(variableName.Length, 10))))), + Token(SyntaxKind.CommaToken), + Argument(TestCase.GetExpressionSyntax(variableName)) + } + )))); + } } public class MethodSignature diff --git a/Tree/Scope.cs b/Tree/Scope.cs index b643190..b48ac0f 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -165,7 +165,7 @@ public void AddStructType(string typeName, List structFields) #region Aggregate Scopes methods /// - /// Combines the list of Variables from all parent scopes. Respects strict mode restrictions + /// Combines the list of Variables from all parent scopes. /// /// /// From c85f284644fbb4e629e27866b3c785ed7bd11f44 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Sep 2021 15:34:33 -0700 Subject: [PATCH 065/149] Update operator to have render text --- Tree/Operators.cs | 92 ++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/Tree/Operators.cs b/Tree/Operators.cs index c0dfd2d..f627c8b 100644 --- a/Tree/Operators.cs +++ b/Tree/Operators.cs @@ -30,7 +30,8 @@ public struct Operator public Primitive InputTypes; public Primitive ReturnType; public SyntaxKind Oper; - private string renderText; + private readonly string renderText; + private readonly string sampleOperation; public bool HasFlag(OpFlags flag) { @@ -46,58 +47,59 @@ public bool HasReturnType(Primitive valueType) private static readonly List operators = new List() { - new Operator(SyntaxKind.UnaryPlusExpression, "+i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.UnaryMinusExpression, "-i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.PreIncrementExpression, "++i", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PreDecrementExpression, "--i", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostIncrementExpression, "i++", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostDecrementExpression, "i--", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.LogicalNotExpression, "!i", Primitive.Boolean, Primitive.Boolean, OpFlags.Unary | OpFlags.Logical), - new Operator(SyntaxKind.BitwiseNotExpression, "~i", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.UnaryPlusExpression, "+", "+i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.UnaryMinusExpression, "-", "-i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(SyntaxKind.PreIncrementExpression, "++", "++i", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PreDecrementExpression, "--", "--i", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostIncrementExpression, "++", "i++", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.PostDecrementExpression, "--", "i--", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(SyntaxKind.LogicalNotExpression, "!", "!i", Primitive.Boolean, Primitive.Boolean, OpFlags.Unary | OpFlags.Logical), + new Operator(SyntaxKind.BitwiseNotExpression, "~", "~i", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), //new Operator(SyntaxKind.TypeOfExpression, "typeof(i)", OpFlags.Unary), - new Operator(SyntaxKind.AddExpression, "i+j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.String), - new Operator(SyntaxKind.AddExpression, "i concat j", Primitive.String, Primitive.String, OpFlags.Binary | OpFlags.String), - new Operator(SyntaxKind.SubtractExpression, "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.MultiplyExpression, "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.DivideExpression, "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), - new Operator(SyntaxKind.ModuloExpression, "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.LeftShiftExpression, "i<>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), - - new Operator(SyntaxKind.SimpleAssignmentExpression, "i=j", Primitive.Any | Primitive.Struct, Primitive.Any | Primitive.Struct, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.AddAssignmentExpression, "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), - new Operator(SyntaxKind.SubtractAssignmentExpression, "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.MultiplyAssignmentExpression, "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.DivideAssignmentExpression, "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), - new Operator(SyntaxKind.ModuloAssignmentExpression, "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.LeftShiftAssignmentExpression, "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - new Operator(SyntaxKind.RightShiftAssignmentExpression, "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - - new Operator(SyntaxKind.LogicalAndExpression, "i&&j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), - new Operator(SyntaxKind.LogicalOrExpression, "i||j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + new Operator(SyntaxKind.AddExpression, "+", "i+j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.String), + new Operator(SyntaxKind.AddExpression, "+", "i concat j", Primitive.String, Primitive.String, OpFlags.Binary | OpFlags.String), + new Operator(SyntaxKind.SubtractExpression, "-", "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.MultiplyExpression, "*", "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.DivideExpression, "/", "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), + new Operator(SyntaxKind.ModuloExpression, "%", "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.LeftShiftExpression, "<<", "i<>", "i>>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), + + new Operator(SyntaxKind.SimpleAssignmentExpression, "=", "i=j", Primitive.Any | Primitive.Struct, Primitive.Any | Primitive.Struct, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.AddAssignmentExpression, "+=", "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), + new Operator(SyntaxKind.SubtractAssignmentExpression, "-=", "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.MultiplyAssignmentExpression, "*=", "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.DivideAssignmentExpression, "/=", "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), + new Operator(SyntaxKind.ModuloAssignmentExpression, "%=", "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.LeftShiftAssignmentExpression, "<<=", "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + new Operator(SyntaxKind.RightShiftAssignmentExpression, ">>=", "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + + new Operator(SyntaxKind.LogicalAndExpression, "&&", "i&&j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + new Operator(SyntaxKind.LogicalOrExpression, "||", "i||j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), //TODO: below can also be logical as per https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators - new Operator(SyntaxKind.BitwiseAndExpression, "i&j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.BitwiseOrExpression, "i|j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.ExclusiveOrExpression, "i^j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - - new Operator(SyntaxKind.AndAssignmentExpression, "i&=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.OrAssignmentExpression, "i|=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, "i^=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - - new Operator(SyntaxKind.LessThanExpression, "ij", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.GreaterThanOrEqualExpression, "i>=j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.EqualsExpression, "i==j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.NotEqualsExpression, "i!=j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) + new Operator(SyntaxKind.BitwiseAndExpression, "&", "i&j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.BitwiseOrExpression, "|", "i|j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(SyntaxKind.ExclusiveOrExpression, "^", "i^j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + + new Operator(SyntaxKind.AndAssignmentExpression, "&=", "i&=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.OrAssignmentExpression, "|=", "i|=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, "^=", "i^=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + + new Operator(SyntaxKind.LessThanExpression, "<", "i", "i>j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.GreaterThanOrEqualExpression, ">=", "i>=j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(SyntaxKind.EqualsExpression, "==", "i==j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(SyntaxKind.NotEqualsExpression, "!=", "i!=j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) }; - private Operator(SyntaxKind oper, string text, Primitive inputTypes, Primitive outputType, OpFlags flags) + private Operator(SyntaxKind oper, string operatorText, string operation, Primitive inputTypes, Primitive outputType, OpFlags flags) { Oper = oper; - renderText = text; + renderText = operatorText; + sampleOperation = operation; InputTypes = inputTypes; ReturnType = outputType; Flags = flags; From 5ad6036684803f3566da060ed5ece2044b8cbeaa Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Sep 2021 15:35:25 -0700 Subject: [PATCH 066/149] Add Node,Expression,Statement classes --- Expressions/Expression.cs | 12 ++++++++++++ Statements/Statement.cs | 19 +++++++++++++++++++ Tree/Node.cs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 Expressions/Expression.cs create mode 100644 Statements/Statement.cs create mode 100644 Tree/Node.cs diff --git a/Expressions/Expression.cs b/Expressions/Expression.cs new file mode 100644 index 0000000..6179dc8 --- /dev/null +++ b/Expressions/Expression.cs @@ -0,0 +1,12 @@ +using Antigen.Tree; + +namespace Antigen.Expressions +{ + public class Expression : Node + { + public Expression(TestCase testCase) : base(testCase) + { + + } + } +} diff --git a/Statements/Statement.cs b/Statements/Statement.cs new file mode 100644 index 0000000..9e560f7 --- /dev/null +++ b/Statements/Statement.cs @@ -0,0 +1,19 @@ +using Antigen.Tree; + +namespace Antigen.Statements +{ + public class Statement : Node + { + protected string _contents; + + public Statement(TestCase testCase) : base(testCase) + { + + } + + protected virtual void PopulateContent() + { + + } + } +} diff --git a/Tree/Node.cs b/Tree/Node.cs new file mode 100644 index 0000000..cfac76e --- /dev/null +++ b/Tree/Node.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Tree +{ + public class Node + { + protected TestCase _testCase; + + //public virtual void Render(RenderContext renderContext) + //{ + + //} + + public override string ToString() + { + return string.Empty; // base.ToString(); + } + + public Node(TestCase tc) + { + _testCase = tc; + } + } +} From abe9eab600ca4e9883c224f360d33cf61e5a0793 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Sep 2021 15:35:46 -0700 Subject: [PATCH 067/149] Add Expressions classes --- Expressions/AssignExpression.cs | 21 ++++++++++++ Expressions/BinaryExpression.cs | 49 +++++++++++++++++++++++++++ Expressions/ConstantValue.cs | 41 ++++++++++++++++++++++ Expressions/MethodCallExpression.cs | 29 ++++++++++++++++ Expressions/ParenthsizedExpression.cs | 27 +++++++++++++++ Expressions/UnaryExpression.cs | 43 +++++++++++++++++++++++ Expressions/VariableExpression.cs | 28 +++++++++++++++ 7 files changed, 238 insertions(+) create mode 100644 Expressions/AssignExpression.cs create mode 100644 Expressions/BinaryExpression.cs create mode 100644 Expressions/ConstantValue.cs create mode 100644 Expressions/MethodCallExpression.cs create mode 100644 Expressions/ParenthsizedExpression.cs create mode 100644 Expressions/UnaryExpression.cs create mode 100644 Expressions/VariableExpression.cs diff --git a/Expressions/AssignExpression.cs b/Expressions/AssignExpression.cs new file mode 100644 index 0000000..360c7e3 --- /dev/null +++ b/Expressions/AssignExpression.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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen.Expressions +{ + public class AssignExpression : BinaryExpression + { + public AssignExpression(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase, lhs, op, rhs) + { + } + } +} diff --git a/Expressions/BinaryExpression.cs b/Expressions/BinaryExpression.cs new file mode 100644 index 0000000..c86463f --- /dev/null +++ b/Expressions/BinaryExpression.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen.Expressions +{ + public class BinaryExpression : Expression + { + public readonly Expression Left; + public readonly Operator Op; + public readonly Expression Right; + + public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase) + { + Left = lhs; + Op = op; + + if ( + (Op.Oper == SyntaxKind.DivideAssignmentExpression) || + (Op.Oper == SyntaxKind.DivideExpression) || + (Op.Oper == SyntaxKind.ModuloAssignmentExpression) || + (Op.Oper == SyntaxKind.ModuloExpression)) + { + // To avoid divide by zero errors + Right = new AssignExpression(testCase, + new ParenthsizedExpression(testCase, rhs), + Operator.ForSyntaxKind(SyntaxKind.AddExpression), + new ConstantValue(testCase, PRNG.Next(10, 100).ToString())); + } + else + { + Right = rhs; + } + } + + public override string ToString() + { + return $"{Left} {Op} {Right}"; + } + } +} diff --git a/Expressions/ConstantValue.cs b/Expressions/ConstantValue.cs new file mode 100644 index 0000000..eb8aadc --- /dev/null +++ b/Expressions/ConstantValue.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; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; + +namespace Antigen.Expressions +{ + public class ConstantValue : Expression + { + public readonly string Value; + + public ConstantValue(TestCase testCase, ValueType valueType, string value) : base(testCase) + { + if (valueType.PrimitiveType == Primitive.Char) + { + Value = $"'{Value}'"; + return; + } + else if (valueType.PrimitiveType == Primitive.String) + { + Value = $"\"{Value}\""; + return; + } + else if (valueType.PrimitiveType == Primitive.Boolean) + { + Debug.Assert(value == "false" || value == "true"); + } + Value = value; + } + public override string ToString() + { + return $"{Value}"; + } + } +} diff --git a/Expressions/MethodCallExpression.cs b/Expressions/MethodCallExpression.cs new file mode 100644 index 0000000..19b0445 --- /dev/null +++ b/Expressions/MethodCallExpression.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Expressions +{ + public class MethodCallExpression : Expression + { + public readonly string MethodName; + public readonly List Arguments; + + public MethodCallExpression(TestCase testCase, string methodName, List arguments) : base(testCase) + { + MethodName = methodName; + Arguments = arguments; + } + + public override string ToString() + { + return $"{MethodName}({string.Join(", ", Arguments)})"; + } + } +} diff --git a/Expressions/ParenthsizedExpression.cs b/Expressions/ParenthsizedExpression.cs new file mode 100644 index 0000000..04da9f4 --- /dev/null +++ b/Expressions/ParenthsizedExpression.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; + +namespace Antigen.Expressions +{ + public class ParenthsizedExpression : Expression + { + public readonly Node Node; + public ParenthsizedExpression(TestCase testCase, Node node) : base(testCase) + { + Node = node; + } + + public override string ToString() + { + return $"({Node})"; + } + } +} diff --git a/Expressions/UnaryExpression.cs b/Expressions/UnaryExpression.cs new file mode 100644 index 0000000..2a4b4ad --- /dev/null +++ b/Expressions/UnaryExpression.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen.Expressions +{ + public class UnaryExpression : Expression + { + public readonly Expression Expression; + public readonly Operator Op; + + private readonly bool _isPostOperation = false; + + public UnaryExpression(TestCase testCase, Expression expression, Operator op) : base(testCase) + { + Expression = expression; + Op = op; + _isPostOperation = op.Oper == SyntaxKind.PostIncrementExpression || op.Oper == SyntaxKind.PostDecrementExpression; + } + + public override string ToString() + { + return _isPostOperation ? PostOperation() : PreOperation(); + } + + private string PreOperation() + { + return $"{Op}{Expression}"; + } + private string PostOperation() + { + return $"{Expression}{Op}"; + } + } +} diff --git a/Expressions/VariableExpression.cs b/Expressions/VariableExpression.cs new file mode 100644 index 0000000..f214324 --- /dev/null +++ b/Expressions/VariableExpression.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; + +namespace Antigen.Expressions +{ + public class VariableExpression : Node + { + public readonly string Name; + + public VariableExpression(TestCase testCase, string name) : base(testCase) + { + Name = name; + } + + public override string ToString() + { + return Name; + } + } +} From a37ae0cdbcdb5a955a6ddb7ff46275527e4b7c1d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Sep 2021 15:36:32 -0700 Subject: [PATCH 068/149] Add Statement classes --- Statements/AssignStatement.cs | 33 +++++++++++++ Statements/IfElseStatement.cs | 51 ++++++++++++++++++++ Statements/MethodCallStatement.cs | 30 ++++++++++++ Statements/ReturnStatement.cs | 28 +++++++++++ Statements/SwitchStatement.cs | 64 ++++++++++++++++++++++++++ Statements/TryCatchFinallyStatement.cs | 61 ++++++++++++++++++++++++ Statements/VarDeclStatement.cs | 32 +++++++++++++ 7 files changed, 299 insertions(+) create mode 100644 Statements/AssignStatement.cs create mode 100644 Statements/IfElseStatement.cs create mode 100644 Statements/MethodCallStatement.cs create mode 100644 Statements/ReturnStatement.cs create mode 100644 Statements/SwitchStatement.cs create mode 100644 Statements/TryCatchFinallyStatement.cs create mode 100644 Statements/VarDeclStatement.cs diff --git a/Statements/AssignStatement.cs b/Statements/AssignStatement.cs new file mode 100644 index 0000000..8372743 --- /dev/null +++ b/Statements/AssignStatement.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; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Antigen.Tree; + +namespace Antigen.Statements +{ + public class AssignStatement : Statement + { + public readonly Expression Left; + public readonly Operator Op; + public readonly Expression Right; + + public AssignStatement(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase) + { + Left = lhs; + Op = op; + Right = rhs; + } + + public override string ToString() + { + return $"{Left} {Op} {Right};"; + } + } +} diff --git a/Statements/IfElseStatement.cs b/Statements/IfElseStatement.cs new file mode 100644 index 0000000..cbd6f97 --- /dev/null +++ b/Statements/IfElseStatement.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; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class IfElseStatement : Statement + { + public readonly Expression Condition; + public readonly List IfBody; + public readonly List ElseBody; + + public IfElseStatement(TestCase testCase, Expression condition, List ifBody, List elseBody) : base(testCase) + { + Condition = condition; + IfBody = ifBody; + ElseBody = elseBody; + + PopulateContent(); + } + + protected override void PopulateContent() + { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.AppendLine($"if ({Condition})"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, IfBody)); + strBuilder.AppendLine("}"); + if (ElseBody != null && ElseBody.Count > 0) + { + strBuilder.AppendLine("else"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, ElseBody)); + strBuilder.AppendLine("}"); + } + _contents = strBuilder.ToString(); + } + + public override string ToString() + { + return _contents; + } + } +} diff --git a/Statements/MethodCallStatement.cs b/Statements/MethodCallStatement.cs new file mode 100644 index 0000000..c4c5a72 --- /dev/null +++ b/Statements/MethodCallStatement.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.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class MethodCallStatement : Statement + { + public readonly string MethodName; + public readonly List Arguments; + + public MethodCallStatement(TestCase testCase, string methodName, List arguments) : base(testCase) + { + MethodName = methodName; + Arguments = arguments; + } + + public override string ToString() + { + return $"{MethodName}({string.Join(", ", Arguments)});"; + } + } +} diff --git a/Statements/ReturnStatement.cs b/Statements/ReturnStatement.cs new file mode 100644 index 0000000..424548a --- /dev/null +++ b/Statements/ReturnStatement.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.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class ReturnStatement : Statement + { + public readonly Expression Expression; + + public ReturnStatement(TestCase testCase, Expression expression) : base(testCase) + { + Expression = expression; + } + + public override string ToString() + { + return $"return {Expression};"; + } + } +} diff --git a/Statements/SwitchStatement.cs b/Statements/SwitchStatement.cs new file mode 100644 index 0000000..1a35bd4 --- /dev/null +++ b/Statements/SwitchStatement.cs @@ -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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Expressions; + +namespace Antigen.Statements +{ + public class SwitchStatement : Statement + { + public readonly Expression SwitchExpr; + public readonly List>> Cases; + public readonly List DefaultBody; + + public SwitchStatement(TestCase testCase, + Expression switchExpr, List>> cases, List defaultBody) : base(testCase) + { + SwitchExpr = switchExpr; + Cases = cases; + DefaultBody = defaultBody; + + PopulateContent(); + } + + public override string ToString() + { + return _contents; + } + + protected override void PopulateContent() + { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.AppendLine($"switch ({SwitchExpr})"); + strBuilder.AppendLine("{"); + + if (Cases != null && Cases.Count > 0) + { + foreach (var caseClause in Cases) + { + strBuilder.AppendLine($"case {caseClause.Item1}:"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, caseClause.Item2)); + strBuilder.AppendLine("break;"); + strBuilder.AppendLine("}"); + } + } + + strBuilder.AppendLine($"default:"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, DefaultBody)); + strBuilder.AppendLine("break;"); + strBuilder.AppendLine("}"); + + strBuilder.AppendLine("}"); + + _contents = strBuilder.ToString(); + } + } +} diff --git a/Statements/TryCatchFinallyStatement.cs b/Statements/TryCatchFinallyStatement.cs new file mode 100644 index 0000000..850637a --- /dev/null +++ b/Statements/TryCatchFinallyStatement.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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class TryCatchFinallyStatement : Statement + { + public readonly List TryBody; + public readonly List>> CatchBodies; + public readonly List FinallyBody; + + public TryCatchFinallyStatement(TestCase testCase, + List tryBody, List>> catchBodies, List finallyBody) : base(testCase) + { + TryBody = tryBody; + CatchBodies = catchBodies; + FinallyBody = finallyBody; + + PopulateContent(); + } + + public override string ToString() + { + return _contents; + } + + protected override void PopulateContent() + { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.AppendLine("try"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, TryBody)); + strBuilder.AppendLine("}"); + if (CatchBodies != null && CatchBodies.Count > 0) + { + foreach (var catchClause in CatchBodies) + { + strBuilder.AppendLine($"catch ({catchClause.Item1})"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, catchClause.Item2)); + strBuilder.AppendLine("}"); + } + } + if (FinallyBody != null && FinallyBody.Count > 0) + { + strBuilder.AppendLine($"finally"); + strBuilder.AppendLine("{"); + strBuilder.AppendLine(string.Join(Environment.NewLine, FinallyBody)); + strBuilder.AppendLine("}"); + } + _contents = strBuilder.ToString(); + } + } +} diff --git a/Statements/VarDeclStatement.cs b/Statements/VarDeclStatement.cs new file mode 100644 index 0000000..5a10084 --- /dev/null +++ b/Statements/VarDeclStatement.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.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class VarDeclStatement : Statement + { + public readonly string TypeName; + public readonly string VariableName; + public readonly Expression Expression; + + public VarDeclStatement(TestCase testCase, string typeName, string variableName, Expression rhs) : base(testCase) + { + TypeName = typeName; + VariableName = variableName; + Expression = rhs; + } + + public override string ToString() + { + return $"{TypeName} {VariableName} = {Expression};"; + } + } +} From e0e39269b1b5e8bdbb76bbb461415f835a234f1f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Sep 2021 15:36:45 -0700 Subject: [PATCH 069/149] Update Loop classes to use new design --- Statements/DoWhileStatement.cs | 70 +++++----- Statements/ForStatement.cs | 112 +++++++-------- Statements/LoopStatement.cs | 243 ++++++++++++++++----------------- Statements/WhileStatement.cs | 63 ++++----- 4 files changed, 242 insertions(+), 246 deletions(-) diff --git a/Statements/DoWhileStatement.cs b/Statements/DoWhileStatement.cs index 64b603d..678d9bd 100644 --- a/Statements/DoWhileStatement.cs +++ b/Statements/DoWhileStatement.cs @@ -1,53 +1,51 @@ -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.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Text; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - +using Antigen.Expressions; namespace Antigen.Statements { public class DoWhileStatement : LoopStatement { - public DoWhileStatement(TestCase tc) : base(tc) {} + public DoWhileStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : + base(tc, nestNum, numOfSecondaryVars, bounds, loopBody) + { + PopulateContent(); + } - public override List Generate(bool labels) + protected override void PopulatePreLoopBody() { - List result = new List(); + // Induction variables to be initialized outside the loop + loopBodyBuilder.AppendLine(GenerateIVInitCode()); - VariableDeclarationSyntax initCode = GenerateIVInitCode(false); - if (initCode != null) - { - result.Add(LocalDeclarationStatement(initCode)); - } + loopBodyBuilder.AppendLine("do {"); // Add step/break condition at the beginning - List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); - - // Add actual loop body - loopBody.AddRange(GetLoopBody()); - - // Add step/break condition at the end - loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); - - // guard condition - ExpressionSyntax condition = GenerateIVLoopGuardCode(); - if (condition == null) - { - condition = Bounds; - } - else - { - condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, Bounds); - } - result.Add(DoStatement(Block(loopBody), condition)); - Debug.Assert(HasSuccessfullyGenerated(), "DoWhileStatement didn't generate properly. Please check the loop variables."); + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false))); + } - return result; + protected override void PopulatePostLoopBody() + { + // Add step/break condition at the beginning + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true))); + loopBodyBuilder.AppendLine("} while("); + + loopBodyBuilder.Append($"({Bounds})"); + + string loopGuardCondition = GenerateIVLoopGuardCode(); + if (!string.IsNullOrEmpty(loopGuardCondition)) + loopBodyBuilder.Append($" && ({loopGuardCondition})"); + + loopBodyBuilder.AppendLine("');"); + + Debug.Assert(HasSuccessfullyGenerated(), "DoWhileStatement didn't generate properly. Please check the loop variables."); } } + } + diff --git a/Statements/ForStatement.cs b/Statements/ForStatement.cs index c3d3657..2cf7ce6 100644 --- a/Statements/ForStatement.cs +++ b/Statements/ForStatement.cs @@ -5,91 +5,95 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Text; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - +using Antigen.Expressions; namespace Antigen.Statements { + public enum Kind + { + SimpleLoop, + NormalLoop, + ComplexLoop + } + public class ForStatement : LoopStatement { - public List symTableLog = new List(); + public readonly Expression LoopStep; + public readonly Kind LoopKind; + public readonly string LoopVar; - public ExpressionSyntax LoopStep; - public Kind LoopKind; - public enum Kind + public ForStatement( + TestCase tc, string loopVar, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody, Expression loopStep, Kind loopKind) : + base(tc, nestNum, numOfSecondaryVars, bounds, loopBody) { - SimpleLoop, - NormalLoop, - ComplexLoop - } + LoopVar = loopVar; + LoopStep = loopStep; + LoopKind = loopKind; - public ForStatement(TestCase tc) : base(tc) {} + loopBodyBuilder = new StringBuilder(); - public override List Generate(bool labels) - { - List result = new List(); + PopulateContent(); + } + protected override void PopulatePreLoopBody() + { // Induction variables to be initialized outside the loop - VariableDeclarationSyntax initCode = GenerateIVInitCode(false); - if (initCode != null) - { - result.Add(LocalDeclarationStatement(initCode)); - } + loopBodyBuilder.AppendLine(GenerateIVInitCode(false)); + + // induction variable initialization + loopBodyBuilder.Append($"for({GenerateIVInitCode(true)};"); + + // condition + string guardCode = GenerateIVLoopGuardCode(); + loopBodyBuilder.Append(guardCode); - // guard condition - ExpressionSyntax condition = GenerateIVLoopGuardCode(); if (LoopKind == Kind.NormalLoop || LoopKind == Kind.ComplexLoop) { - ExpressionSyntax boundCond = BinaryExpression(SyntaxKind.LessThanExpression, TestCase.GetExpressionSyntax(LoopVar), Bounds); - if (condition == null) - { - condition = boundCond; - } - else - { - condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, boundCond); - } + if (!string.IsNullOrEmpty(guardCode)) + loopBodyBuilder.Append(" &&"); + loopBodyBuilder.Append($" {LoopVar} < ({Bounds})"); } + loopBodyBuilder.Append(';'); // induction variables to be incr/decr - SeparatedSyntaxList incrementors = GenerateIVStepCode(); + string stepCode = GenerateIVStepCode(); + loopBodyBuilder.Append(stepCode); + if (LoopKind == Kind.NormalLoop) { - incrementors.Add(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, TestCase.GetExpressionSyntax(LoopVar))); + if (!string.IsNullOrEmpty(stepCode)) + { + loopBodyBuilder.Append(" ,"); + } + loopBodyBuilder.Append($" {LoopVar}++"); } else if (LoopKind == Kind.ComplexLoop) { - incrementors.Add(LoopStep); + if (!string.IsNullOrEmpty(stepCode)) + { + loopBodyBuilder.Append(','); + } + loopBodyBuilder.Append(' '); + loopBodyBuilder.Append(LoopStep); } + loopBodyBuilder.AppendLine(")"); - // Add step/break condition at the beginning - List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); + loopBodyBuilder.AppendLine("{"); - // Add actual loop body - loopBody.AddRange(GetLoopBody()); + // Add step/break condition at the beginning + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false))); + } + protected override void PopulatePostLoopBody() + { // Add step/break condition at the end - loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true))); - ForStatementSyntax forStmt = ForStatement(Block(loopBody)); - - VariableDeclarationSyntax declaration = GenerateIVInitCode(true); - if (declaration != null) - { - forStmt = forStmt.WithDeclaration(declaration); - } - forStmt = forStmt.WithCondition(condition).WithIncrementors(incrementors); - result.Add(forStmt); Debug.Assert(HasSuccessfullyGenerated(), "ForStatement didn't generate properly. Please check the loop variables."); - return result; + loopBodyBuilder.AppendLine("}"); } - }; + } } diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 3aa3571..0111e14 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -8,11 +8,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Statements { @@ -90,7 +90,7 @@ public class LoopControlParameters public class InductionVariable { - private static int NumOfIterations = 3; + private static readonly int s_numOfIterations = 3; public bool IsPrimary; public string Name; public LoopControlParameters LoopParameters; @@ -115,13 +115,13 @@ public override string ToString() if (IsPrimary) { if (LoopParameters.IsStepBeforeBreakCondition) - return String.Format("({0} = {1} ; {4}, {0} {2} {3}; )", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + return string.Format("({0} = {1} ; {4}, {0} {2} {3}; )", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); else - return String.Format("({0} = {1} ; {0} {2} {3}; {4})", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); + return string.Format("({0} = {1} ; {0} {2} {3}; {4})", Name, __loopStart, getLoopControlOperator(true), __loopEnd, GetLoopStep()); } else { - return String.Format("({0} = {1} ; ; {2})", Name, __loopStart, GetLoopStep()); + return string.Format("({0} = {1} ; ; {2})", Name, __loopStart, GetLoopStep()); } } @@ -145,14 +145,14 @@ public bool HasSuccessfullyGenerated() /// Returns value of loopinduction variable with which it should start the loop /// /// - internal ExpressionSyntax GetLoopStart() + internal string GetLoopStart() { __loopStart = 0; // If loop starts with invariant then _loopvar = loopInvariant; if (LoopParameters.IsLoopStartFromInvariant) - return IdentifierName(LoopInvariantName); + return LoopInvariantName; - int loopStartValue = (InductionVariable.NumOfIterations * LoopParameters.LoopInductionChangeFactor); + int loopStartValue = (InductionVariable.s_numOfIterations * LoopParameters.LoopInductionChangeFactor); if (LoopParameters.IsForwardLoop) loopStartValue += LoopParameters.LoopInitValueVariation; @@ -161,20 +161,16 @@ internal ExpressionSyntax GetLoopStart() __loopStart = (LoopParameters.IsForwardLoop ? -1 : 1) * loopStartValue; - return BinaryExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.SubtractExpression : SyntaxKind.AddExpression, - IdentifierName(LoopInvariantName), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(loopStartValue))); - //return String.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "-" : "+", loopStartValue.ToString()); + return string.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "-" : "+", loopStartValue.ToString()); } /// /// Returns value of loopinduction variable with which it should end the loop /// /// - internal ExpressionSyntax GetLoopEnd() + internal string GetLoopEnd() { - int numOfIterations = InductionVariable.NumOfIterations; + int numOfIterations = InductionVariable.s_numOfIterations; __loopEnd = 0; // If loop doesn't start with invariant, it ends with loopInvariant : __loopvar = loopInvariant - N; __loopvar < loopInvariant; if (!LoopParameters.IsLoopStartFromInvariant) @@ -192,13 +188,13 @@ internal ExpressionSyntax GetLoopEnd() __loopEnd = (LoopParameters.IsForwardLoop ? 1 : -1) * loopEndValue; if (loopEndValue == 0) - return IdentifierName(LoopInvariantName); + { + return LoopInvariantName; + } else - return BinaryExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.AddExpression : SyntaxKind.SubtractExpression, - IdentifierName(LoopInvariantName), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(loopEndValue))); - //return String.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "+" : "-", loopEndValue.ToString()); + { + return string.Format("{0} {1} {2}", LoopInvariantName, LoopParameters.IsForwardLoop ? "+" : "-", loopEndValue.ToString()); + } } /// @@ -206,24 +202,17 @@ internal ExpressionSyntax GetLoopEnd() /// than loop control statements, call this only for secondary induction variables. /// /// - internal ExpressionSyntax GetLoopStepForSecondaryIV() + internal string GetLoopStepForSecondaryIV() { Debug.Assert(!IsPrimary, "Try to get loop step for primary induction variable."); int selectedChangeFactor = GetRandomInductionChangeFactor(); if (selectedChangeFactor == 1) { - return PostfixUnaryExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.PostIncrementExpression : SyntaxKind.PostDecrementExpression, - IdentifierName(Name)); - //return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; + return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; } else { - return AssignmentExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.AddAssignmentExpression : SyntaxKind.SubtractAssignmentExpression, - IdentifierName(Name), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(selectedChangeFactor))); - //return String.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", selectedChangeFactor); + return string.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", selectedChangeFactor); } } @@ -242,22 +231,15 @@ private int GetRandomInductionChangeFactor() /// /// /// - internal ExpressionSyntax GetLoopStep() + internal string GetLoopStep() { if (LoopParameters.LoopInductionChangeFactor == 1) { - return PostfixUnaryExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.PostIncrementExpression : SyntaxKind.PostDecrementExpression, - IdentifierName(Name)); - //return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; + return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; } else { - return AssignmentExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.AddAssignmentExpression : SyntaxKind.SubtractAssignmentExpression, - IdentifierName(Name), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(LoopParameters.LoopInductionChangeFactor))); - //return String.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", LoopParameters.LoopInductionChangeFactor); + return string.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", LoopParameters.LoopInductionChangeFactor); } } @@ -266,35 +248,28 @@ internal ExpressionSyntax GetLoopStep() /// Returns the loop IV access code +/- change factor /// /// - internal ExpressionSyntax GetLoopIVAccess() + internal string GetLoopIVAccess() { // 5% of time generate '0' for change factor - return BinaryExpression( - LoopParameters.IsForwardLoop ? SyntaxKind.AddExpression : SyntaxKind.SubtractExpression, - IdentifierName(Name), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(GetRandomInductionChangeFactor()))); - - //return String.Format("{0} {1} {2}", Name, LoopParameters.IsForwardLoop ? "+" : "-", GetRandomInductionChangeFactor()); + return string.Format("{0} {1} {2}", Name, LoopParameters.IsForwardLoop ? "+" : "-", GetRandomInductionChangeFactor()); } /// /// Returns the guard condition for the loop. Loop will execute as long as this condition is true. /// /// - internal ExpressionSyntax GetLoopGuardCondition() + internal string GetLoopGuardCondition() { - return BinaryExpression(getLoopControlOperator(true).Oper, IdentifierName(Name), GetLoopEnd()); - //return String.Format("({0} {1} {2})", Name, getLoopControlOperator(true), GetLoopEnd()); + return string.Format("({0} {1} {2})", Name, getLoopControlOperator(true), GetLoopEnd()); } /// /// Returns the break condition for the loop. Loop will terminate when this condition is true. /// /// - internal ExpressionSyntax GetLoopBreakCondition() + internal string GetLoopBreakCondition() { - return BinaryExpression(getLoopControlOperator(false).Oper, IdentifierName(Name), GetLoopEnd()); - //return String.Format("({0} {1} {2})", Name, getLoopControlOperator(false), GetLoopEnd()); + return string.Format("({0} {1} {2})", Name, getLoopControlOperator(false), GetLoopEnd()); } /// @@ -308,7 +283,9 @@ private Operator getLoopControlOperator(bool isFetchingForGuardCondition) // If break operator is '==' then guard operator is '!='. This is same regardless this is forward/backward loop if (result.Oper == SyntaxKind.EqualsExpression && isFetchingForGuardCondition) + { result = Operator.ForSyntaxKind(SyntaxKind.NotEqualsExpression); // "!="; + } // If this is forward loop and we are fetching for break condition, no need to flip the operator else if (LoopParameters.IsForwardLoop && !isFetchingForGuardCondition) { } @@ -319,12 +296,14 @@ private Operator getLoopControlOperator(bool isFetchingForGuardCondition) // If this is reverse loop and we are fetching for break condition OR this is forward loop and we are fetching for guard condition, // then flip the operator else - result = flipOperator(result); + { + result = FlipOperator(result); + } return result; } - private Operator flipOperator(Operator oldOperator) + private static Operator FlipOperator(Operator oldOperator) { Operator newOperator; switch (oldOperator.Oper) @@ -351,15 +330,16 @@ private Operator flipOperator(Operator oldOperator) #endregion } - public class LoopStatement + public class LoopStatement : Statement { private int _nestNum; private int _noOfSecondaryInductionVariables; private List _inductionVariables; + protected StringBuilder loopBodyBuilder = new StringBuilder(); #region Properties - public ExpressionSyntax Bounds; + public Expression Bounds; public bool IsContinueAllowedInLoopBody { @@ -373,7 +353,7 @@ public bool IsContinueAllowedInLoopBody public bool IsWrappedInFunction = false; public bool IsUseEvalIsWrappedInFunction = false; public bool IsSnippetGenerated = false; - protected List Body = new List(); + protected List Body = new List(); //TODO-future: labels for goto //public List Labels = new List(); public List InductionVariables @@ -439,7 +419,6 @@ protected List InductionVariableNamesInitializedOutsideLoop } protected bool offlineReduceOnly = false; - public string LoopVar; public int NestNum { get { return _nestNum; } @@ -500,13 +479,13 @@ private void ValidateInductionVariablesParams() //if (!inductionVariable.LoopParameters.IsLoopInvariantVariableUsed) //{ // string arrayVariableToAccessForLength = LocalScope.GetRandomArrayObject(SymbolAction.Read); - // if (!String.IsNullOrEmpty(arrayVariableToAccessForLength)) + // if (!string.IsNullOrEmpty(arrayVariableToAccessForLength)) // { - // inductionVariable.LoopInvariantName = String.Format("{0}.length", arrayVariableToAccessForLength); + // inductionVariable.LoopInvariantName = string.Format("{0}.length", arrayVariableToAccessForLength); // } //} - if (String.IsNullOrEmpty(inductionVariable.LoopInvariantName)) + if (string.IsNullOrEmpty(inductionVariable.LoopInvariantName)) inductionVariable.LoopInvariantName = Constants.LoopInvariantName; } } @@ -523,7 +502,7 @@ protected bool HasSuccessfullyGenerated() } #endregion - public void AddToBody(StatementSyntax stmt) + public void AddToBody(Statement stmt) { Body.Add(stmt); } @@ -533,9 +512,24 @@ public void LogVariable(string name) Body.Add(TestMethod.GetLogInvokeStatement(name)); } - public LoopStatement(TestCase tc) + public LoopStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : base(tc) { TC = tc; + NestNum = nestNum; + NumOfSecondaryInductionVariables = numOfSecondaryVars; + Bounds = bounds; + Body = loopBody; + } + + protected override void PopulateContent() + { + loopBodyBuilder = new StringBuilder(); + + PopulatePreLoopBody(); + PopulateLoopBody(); + PopulatePostLoopBody(); + + _contents = loopBodyBuilder.ToString(); } public string GetImplicitLoopVar() @@ -548,23 +542,47 @@ public virtual List Generate(bool labels) return null; } - protected List GetLoopBody() + protected virtual void PopulatePreLoopBody() + { + } + + protected virtual void PopulateLoopBody() { // load the value of Property once instead of reading from Property everytime because it queries the list of IVs - bool isContinueAllowedInLoopBody = IsContinueAllowedInLoopBody; + //bool isContinueAllowedInLoopBody = IsContinueAllowedInLoopBody; -#if DEBUG - foreach (StatementSyntax sm in Body) - { - if (sm is ContinueStatementSyntax) - { - Debug.Assert(isContinueAllowedInLoopBody, "continue is not allowed in loop since break condition is at the end of loop."); - } - } -#endif - return Body; + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, Body)); + //foreach (var sm in Body) + //{ + //if (sm is ContinueStatement) + //{ + // Debug.Assert(isContinueAllowedInLoopBody, "continue is not allowed in loop since break condition is at the end of loop."); + //} + // loopBodyBuilder.AppendLine(sm); + //} } + protected virtual void PopulatePostLoopBody() + { + } + +// protected List GetLoopBody() +// { +// // load the value of Property once instead of reading from Property everytime because it queries the list of IVs +// bool isContinueAllowedInLoopBody = IsContinueAllowedInLoopBody; + +//#if DEBUG +// foreach (StatementSyntax sm in Body) +// { +// if (sm is ContinueStatementSyntax) +// { +// Debug.Assert(isContinueAllowedInLoopBody, "continue is not allowed in loop since break condition is at the end of loop."); +// } +// } +//#endif +// return Body; +// } + #region Loop induction code generation private List generateComments() @@ -572,9 +590,9 @@ private List generateComments() return InductionVariables.Select(iv => iv.ToString()).ToList(); } - protected VariableDeclarationSyntax GenerateIVInitCode(bool isInitLoopHead = false) + protected string GenerateIVInitCode(bool isInitLoopHead = false) { - List loopInits = new List(); + List loopInits = new List(); // Induction variables to be initialized outside the loop foreach (var inductionVar in InductionVariables) @@ -583,50 +601,38 @@ protected VariableDeclarationSyntax GenerateIVInitCode(bool isInitLoopHead = fal inductionVar.LoopParameters.IsInitInLoopHeader == isInitLoopHead) { inductionVar.isLoopInitGenerated = true; - loopInits.Add(VariableDeclarator(Identifier(inductionVar.Name)).WithInitializer(EqualsValueClause(inductionVar.GetLoopStart()))); + loopInits.Add(string.Format("{0} = {1}", inductionVar.Name, inductionVar.GetLoopStart())); } } if (loopInits.Count > 0) { - return VariableDeclaration(Helpers.GetToken(SyntaxKind.IntKeyword), SeparatedList(loopInits)); + return $"int {string.Join(",", loopInits)};"; } - return null; + + return string.Empty; } - protected SeparatedSyntaxList GenerateIVStepCode() + protected string GenerateIVStepCode() { - // Induction variables to be incr/decr in loop body - List loopInits = new List(); - List finalInits = new List(); - - for (int i = 0; i < InductionVariables.Count; i++) - { - InductionVariable inductionVariable = InductionVariables[i]; - if (inductionVariable.LoopParameters.IsStepInLoopHeader) - { - inductionVariable.isLoopStepGenerated = true; - loopInits.Add(inductionVariable.GetLoopStep()); - } - } + List loopInits = new List(); - if (loopInits.Count > 0) + // Secondary induction variables to be incr/decr in loop body + foreach (var inductionVar in InductionVariables) { - finalInits.Add(loopInits[0]); - for (int i = 1; i < loopInits.Count; i++) + if (inductionVar.LoopParameters.IsStepInLoopHeader) { - finalInits.Add(Token(SyntaxKind.CommaToken)); - finalInits.Add(loopInits[i]); + inductionVar.isLoopStepGenerated = true; + loopInits.Add(string.Format("{0}", inductionVar.GetLoopStep())); } } - - return SeparatedList(finalInits); + return string.Join(", ", loopInits); } - protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCondAtTheEnd) + protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCondAtTheEnd) { - List loopBreaks = new List(); - List loopPreCondSteps = new List(); - List loopPostCondSteps = new List(); + List loopBreaks = new List(); + List loopPreCondSteps = new List(); + List loopPostCondSteps = new List(); // Generate break and step condition for primary variables foreach (var inductionVar in PrimaryInductionVariables) @@ -636,7 +642,7 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo inductionVar.LoopParameters.IsBreakCondAtEndOfLoopBody == isCodeForBreakCondAtTheEnd) // If decided to add step at end of loop body and this is end of loop body { inductionVar.isLoopBreakGenerated = true; - loopBreaks.Add(IfStatement(inductionVar.GetLoopBreakCondition(), Block(BreakStatement()))); + loopBreaks.Add(string.Format("if {0} break;", inductionVar.GetLoopBreakCondition())); } } @@ -650,11 +656,11 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo inductionVar.isLoopStepGenerated = true; if (inductionVar.LoopParameters.IsStepBeforeBreakCondition) { - loopPreCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); + loopPreCondSteps.Add(string.Format("{0};", inductionVar.GetLoopStep())); } else { - loopPostCondSteps.Add(ExpressionStatement(inductionVar.GetLoopStep())); + loopPostCondSteps.Add(string.Format("{0};", inductionVar.GetLoopStep())); } } } @@ -663,9 +669,9 @@ protected List GenerateIVBreakAndStepCode(bool isCodeForBreakCo return loopBreaks; } - protected ExpressionSyntax GenerateIVLoopGuardCode() + protected string GenerateIVLoopGuardCode() { - ExpressionSyntax guardCondition = null; + List loopGuardConditions = new List(); // Secondary induction variables to be incr/decr in loop body foreach (var inductionVariable in PrimaryInductionVariables) @@ -674,18 +680,11 @@ protected ExpressionSyntax GenerateIVLoopGuardCode() if (inductionVariable.LoopParameters.IsBreakCondInLoopHeader) { inductionVariable.isLoopBreakGenerated = true; - var currCondition = inductionVariable.GetLoopGuardCondition(); - if (guardCondition != null) - { - guardCondition = BinaryExpression(SyntaxKind.LogicalAndExpression, guardCondition, currCondition); - } - else - { - guardCondition = currCondition; - } + loopGuardConditions.Add(inductionVariable.GetLoopGuardCondition()); } } - return guardCondition; + + return string.Join(" && ", loopGuardConditions); } #endregion diff --git a/Statements/WhileStatement.cs b/Statements/WhileStatement.cs index 49f6de6..84342f4 100644 --- a/Statements/WhileStatement.cs +++ b/Statements/WhileStatement.cs @@ -5,52 +5,47 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Text; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using Antigen.Expressions; namespace Antigen.Statements { public class WhileStatement : LoopStatement { - public WhileStatement(TestCase tc) : base(tc) {} + public WhileStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : + base(tc, nestNum, numOfSecondaryVars, bounds, loopBody) + { + PopulateContent(); + } - public override List Generate(bool labels) + protected override void PopulatePreLoopBody() { - List result = new List(); + // Induction variables to be initialized outside the loop + loopBodyBuilder.AppendLine(GenerateIVInitCode()); + + loopBodyBuilder.Append("while("); + loopBodyBuilder.Append($"({Bounds})"); - VariableDeclarationSyntax initCode = GenerateIVInitCode(false); - if (initCode != null) - { - result.Add(LocalDeclarationStatement(initCode)); - } + string loopGuardCondition = GenerateIVLoopGuardCode(); + if (!string.IsNullOrEmpty(loopGuardCondition)) + loopBodyBuilder.Append($" && ({loopGuardCondition})"); + loopBodyBuilder.Append(')'); + + loopBodyBuilder.AppendLine("{"); // Add step/break condition at the beginning - List loopBody = GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false); - - // Add actual loop body - loopBody.AddRange(GetLoopBody()); - - // Add step/break condition at the end - loopBody.AddRange(GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true)); - - // guard condition - ExpressionSyntax condition = GenerateIVLoopGuardCode(); - if (condition == null) - { - condition = Bounds; - } - else - { - condition = BinaryExpression(SyntaxKind.LogicalAndExpression, condition, Bounds); - } - result.Add(WhileStatement(condition, Block(loopBody))); - Debug.Assert(HasSuccessfullyGenerated(), "WhileStatement didn't generate properly. Please check the loop variables."); + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: false))); + } - return result; + protected override void PopulatePostLoopBody() + { + // Add step/break condition at the beginning + loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true))); + + loopBodyBuilder.AppendLine("}"); + + Debug.Assert(HasSuccessfullyGenerated(), "WhileStatement didn't generate properly. Please check the loop variables."); } } + } From f4ca5b2f514a8a96a89e96a7029c5c4b79f142e8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 9 Sep 2021 00:06:05 -0700 Subject: [PATCH 070/149] Use new design in StatementHelper and ExprHelper --- Expressions/BinaryExpression.cs | 13 +- Expressions/ConstantValue.cs | 96 ++++++++++++- Expressions/Expression.cs | 24 ++++ Expressions/MethodCallExpression.cs | 38 +++++- Expressions/VariableExpression.cs | 2 +- Statements/AssignStatement.cs | 2 +- Statements/IfElseStatement.cs | 2 +- Statements/LoopStatement.cs | 5 - Statements/MethodCallStatement.cs | 10 +- Statements/ReturnStatement.cs | 5 +- Statements/Statement.cs | 23 +++- Statements/VarDeclStatement.cs | 6 +- TestMethod.cs | 205 +++++++++++----------------- Tree/Node.cs | 9 +- 14 files changed, 290 insertions(+), 150 deletions(-) diff --git a/Expressions/BinaryExpression.cs b/Expressions/BinaryExpression.cs index c86463f..7a5706f 100644 --- a/Expressions/BinaryExpression.cs +++ b/Expressions/BinaryExpression.cs @@ -32,8 +32,7 @@ public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expressi // To avoid divide by zero errors Right = new AssignExpression(testCase, new ParenthsizedExpression(testCase, rhs), - Operator.ForSyntaxKind(SyntaxKind.AddExpression), - new ConstantValue(testCase, PRNG.Next(10, 100).ToString())); + Operator.ForSyntaxKind(SyntaxKind.AddExpression), ConstantValue.GetRandomConstantInt()); } else { @@ -41,6 +40,16 @@ public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expressi } } + protected override string GetCode() + { + return base.GetCode(); + } + + protected override void PopulateContent() + { + base.PopulateContent(); + } + public override string ToString() { return $"{Left} {Op} {Right}"; diff --git a/Expressions/ConstantValue.cs b/Expressions/ConstantValue.cs index eb8aadc..447e814 100644 --- a/Expressions/ConstantValue.cs +++ b/Expressions/ConstantValue.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.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -15,7 +16,7 @@ public class ConstantValue : Expression { public readonly string Value; - public ConstantValue(TestCase testCase, ValueType valueType, string value) : base(testCase) + protected ConstantValue(Tree.ValueType valueType, string value) : base(null) { if (valueType.PrimitiveType == Primitive.Char) { @@ -33,9 +34,102 @@ public ConstantValue(TestCase testCase, ValueType valueType, string value) : bas } Value = value; } + public override string ToString() { return $"{Value}"; } + + public static ConstantValue GetRandomConstantInt() + { + return new ConstantValue(Tree.ValueType.ForPrimitive(Primitive.Int), PRNG.Next(10, 100).ToString()); + } + + public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList> numerals) + { + string constantValue; + if ((literalType.PrimitiveType & Primitive.Numeric) != 0) + { + // numeric + int literalValue = PRNG.WeightedChoice(numerals); + constantValue = literalValue.ToString(); + + // If unsigned, and number selected is negative, then flip it + if ((literalType.PrimitiveType & Primitive.UnsignedInteger) != 0) + { + if (literalValue < 0) + { + if (literalValue == int.MinValue) + { + literalValue = int.MaxValue; + } + else + { + literalValue *= -1; + } + } + } + + switch (literalType.PrimitiveType) + { + case Tree.Primitive.Byte: + constantValue = ((byte)(literalValue % byte.MaxValue)).ToString(); + break; + case Tree.Primitive.SByte: + constantValue = ((sbyte)(literalValue % sbyte.MaxValue)).ToString(); + break; + case Tree.Primitive.UShort: + constantValue = ((ushort)(literalValue % ushort.MaxValue)).ToString(); + break; + case Tree.Primitive.Short: + constantValue = ((short)(literalValue % short.MaxValue)).ToString(); + break; + case Tree.Primitive.Int: + case Tree.Primitive.UInt: + case Tree.Primitive.Long: + case Tree.Primitive.ULong: + // already constantValue is populated + break; + case Tree.Primitive.Float: + constantValue = ((float)literalValue + (float)PRNG.Next(5) / PRNG.Next(10, 100)).ToString(); + break; + case Tree.Primitive.Decimal: + constantValue = ((decimal)literalValue + (decimal)PRNG.Next(5) / PRNG.Next(10, 100)).ToString(); + break; + case Tree.Primitive.Double: + constantValue = ((double)literalValue + (double)PRNG.Next(5) / PRNG.Next(10, 100)).ToString(); + break; + default: + Debug.Assert(false, string.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); + constantValue = "1"; + break; + } + } + else + { + // non-numeric + switch (literalType.PrimitiveType) + { + case Tree.Primitive.Boolean: + constantValue = PRNG.Decide(0.5) ? "true" : "false"; + break; + + case Tree.Primitive.Char: + constantValue = Helpers.GetRandomChar().ToString(); + break; + + case Tree.Primitive.String: + constantValue = Helpers.GetRandomString(); + break; + default: + Debug.Assert(false, string.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); + constantValue = "1"; + + break; + } + } + + return new ConstantValue(literalType, constantValue); + } } } diff --git a/Expressions/Expression.cs b/Expressions/Expression.cs index 6179dc8..cea374f 100644 --- a/Expressions/Expression.cs +++ b/Expressions/Expression.cs @@ -4,9 +4,33 @@ namespace Antigen.Expressions { public class Expression : Node { +#if DEBUG + private readonly Dictionary _expressionsCount = new(); +#endif + public Expression(TestCase testCase) : base(testCase) { } + + protected override string Annotate() + { +#if DEBUG + string typeName = GetType().Name; + if (!_expressionsCount.ContainsKey(typeName)) + { + _expressionsCount[typeName] = 0; + } + _expressionsCount[typeName]++; + return $"{ToString() /* E#{_expressionsCount[typeName]}: {typeName} */}"; +#else + return ToString(); +#endif + } + + public override string ToString() + { + return string.Empty; + } } } diff --git a/Expressions/MethodCallExpression.cs b/Expressions/MethodCallExpression.cs index 19b0445..654e80f 100644 --- a/Expressions/MethodCallExpression.cs +++ b/Expressions/MethodCallExpression.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -14,16 +15,49 @@ public class MethodCallExpression : Expression { public readonly string MethodName; public readonly List Arguments; + public readonly List ArgsPassingWays; - public MethodCallExpression(TestCase testCase, string methodName, List arguments) : base(testCase) + public MethodCallExpression(string methodName, List arguments, List passingWays) : base(null) { + Debug.Assert(arguments.Count == passingWays.Count); + MethodName = methodName; Arguments = arguments; + + PopulateContent(); + } + + protected override void PopulateContent() + { + List finalArgs = new List(); + + for (int argId = 0; argId < Arguments.Count; argId++) + { + Expression argument = Arguments[argId]; + ParamValuePassing paramPassing = ArgsPassingWays[argId]; + switch (paramPassing) + { + case ParamValuePassing.None: + finalArgs.Add(argument.ToString()); + break; + case ParamValuePassing.Ref: + finalArgs.Add($"ref {argument}"); + break; + case ParamValuePassing.Out: + finalArgs.Add($"out {argument}"); + break; + default: + Debug.Assert(false, "Unreachable"); + break; + } + } + + _contents = $"{MethodName}({string.Join(", ", finalArgs)})"; } public override string ToString() { - return $"{MethodName}({string.Join(", ", Arguments)})"; + return _contents; } } } diff --git a/Expressions/VariableExpression.cs b/Expressions/VariableExpression.cs index f214324..e3d55ed 100644 --- a/Expressions/VariableExpression.cs +++ b/Expressions/VariableExpression.cs @@ -11,7 +11,7 @@ namespace Antigen.Expressions { - public class VariableExpression : Node + public class VariableExpression : Expression { public readonly string Name; diff --git a/Statements/AssignStatement.cs b/Statements/AssignStatement.cs index 8372743..037b4d4 100644 --- a/Statements/AssignStatement.cs +++ b/Statements/AssignStatement.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; using Antigen.Tree; namespace Antigen.Statements diff --git a/Statements/IfElseStatement.cs b/Statements/IfElseStatement.cs index cbd6f97..7c19416 100644 --- a/Statements/IfElseStatement.cs +++ b/Statements/IfElseStatement.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; namespace Antigen.Statements { diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 0111e14..25a2bbb 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -507,11 +507,6 @@ public void AddToBody(Statement stmt) Body.Add(stmt); } - public void LogVariable(string name) - { - Body.Add(TestMethod.GetLogInvokeStatement(name)); - } - public LoopStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : base(tc) { TC = tc; diff --git a/Statements/MethodCallStatement.cs b/Statements/MethodCallStatement.cs index c4c5a72..97beb45 100644 --- a/Statements/MethodCallStatement.cs +++ b/Statements/MethodCallStatement.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; @@ -14,17 +13,16 @@ namespace Antigen.Statements public class MethodCallStatement : Statement { public readonly string MethodName; - public readonly List Arguments; + public readonly Expression MethodCallExpr; - public MethodCallStatement(TestCase testCase, string methodName, List arguments) : base(testCase) + public MethodCallStatement(TestCase testCase, Expression methodCallExpr) : base(testCase) { - MethodName = methodName; - Arguments = arguments; + MethodCallExpr = methodCallExpr; } public override string ToString() { - return $"{MethodName}({string.Join(", ", Arguments)});"; + return $"{MethodCallExpr};"; } } } diff --git a/Statements/ReturnStatement.cs b/Statements/ReturnStatement.cs index 424548a..81b93d8 100644 --- a/Statements/ReturnStatement.cs +++ b/Statements/ReturnStatement.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; namespace Antigen.Statements { @@ -22,7 +22,8 @@ public ReturnStatement(TestCase testCase, Expression expression) : base(testCase public override string ToString() { - return $"return {Expression};"; + string expression = Expression != null ? Expression.ToString() : string.Empty; + return $"return {expression};"; } } } diff --git a/Statements/Statement.cs b/Statements/Statement.cs index 9e560f7..803219e 100644 --- a/Statements/Statement.cs +++ b/Statements/Statement.cs @@ -4,16 +4,35 @@ namespace Antigen.Statements { public class Statement : Node { - protected string _contents; + +#if DEBUG + private readonly Dictionary _statementsCount = new(); +#endif public Statement(TestCase testCase) : base(testCase) { } - protected virtual void PopulateContent() + + protected override string Annotate() { +#if DEBUG + string typeName = GetType().Name; + if (!_statementsCount.ContainsKey(typeName)) + { + _statementsCount[typeName] = 0; + } + _statementsCount[typeName]++; + return $"{GetCode() /* S#{_statementsCount[typeName]}: {typeName} */}"; +#else + return GetCode(); +#endif + } + protected override string GetCode() + { + return string.Empty; } } } diff --git a/Statements/VarDeclStatement.cs b/Statements/VarDeclStatement.cs index 5a10084..2ea4268 100644 --- a/Statements/VarDeclStatement.cs +++ b/Statements/VarDeclStatement.cs @@ -5,19 +5,19 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; namespace Antigen.Statements { public class VarDeclStatement : Statement { - public readonly string TypeName; + public readonly Tree.ValueType TypeName; public readonly string VariableName; public readonly Expression Expression; - public VarDeclStatement(TestCase testCase, string typeName, string variableName, Expression rhs) : base(testCase) + public VarDeclStatement(TestCase testCase, Tree.ValueType typeName, string variableName, Expression rhs) : base(testCase) { TypeName = typeName; VariableName = variableName; diff --git a/TestMethod.cs b/TestMethod.cs index 81e7e0a..ef3dbf3 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -1,4 +1,5 @@ using Antigen.Config; +using Antigen.Expressions; using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; @@ -64,7 +65,7 @@ protected Scope PopScope(Action trackLocalVariables) return ret; } - internal void LogVariable(IList stmtList, string variableName) + internal void LogVariable(List stmtList, string variableName) { stmtList.Add(GetLogInvokeStatement(variableName)); } @@ -297,7 +298,7 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() /// /// /// - public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) + public Statement StatementHelper(StmtKind stmtKind, int depth) { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); @@ -309,7 +310,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) string variableName = Helpers.GetVariableName(variableType, _variablesCount++); - ExpressionSyntax rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); + Expression rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); // Add all the fields to the scope @@ -322,20 +323,20 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } } - return Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "VarDecl", depth); + return new VarDeclStatement(TC, variableType, variableName, rhs); } case StmtKind.IfElseStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); - ExpressionSyntax conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); + Expression conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); Scope ifBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); Scope elseBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); int ifcount = PRNG.Next(1, TC.Config.MaxStatementCount); - IList ifBody = new List(); + List ifBody = new List(); PushScope(ifBranchScope); for (int i = 0; i < ifcount; i++) @@ -354,7 +355,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(variableName => LogVariable(ifBody, variableName)); // pop 'if' body scope int elsecount = PRNG.Next(1, TC.Config.MaxStatementCount); - IList elseBody = new List(); + List elseBody = new List(); PushScope(elseBranchScope); for (int i = 0; i < elsecount; i++) @@ -372,7 +373,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(elseBody, variableName)); // pop 'else' body scope - return Annotate(IfStatement(conditionExpr, Block(ifBody), ElseClause(Block(elseBody))), "IfElse", depth); + return new IfElseStatement(TC, conditionExpr, ifBody, elseBody); } case StmtKind.AssignStatement: { @@ -400,44 +401,36 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } ExprKind rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); - ExpressionSyntax rhs = ExprHelper(rhsKind, rhsExprType, 0); + Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); + Expression rhs = ExprHelper(rhsKind, rhsExprType, 0); - // For division, make sure that divisor is not 0 - if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) - { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); - } - - return Annotate(ExpressionStatement(AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign", depth); + return new AssignStatement(TC, lhs, assignOper, rhs); } case StmtKind.ForStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); - Scope forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); - ForStatement forStmt = new ForStatement(TC); - forStmt.LoopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); - forStmt.NestNum = depth; - forStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + var forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); + var loopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); + var nestNum = depth; + var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + var forLoopKind = Kind.ComplexLoop; // 50% of the time, we'll make it a simple loop, 25% each normal and complex. if (PRNG.Next(2) == 0) - forStmt.LoopKind = Statements.ForStatement.Kind.SimpleLoop; + forLoopKind = Kind.SimpleLoop; else if (PRNG.Next(2) == 0) - forStmt.LoopKind = Statements.ForStatement.Kind.NormalLoop; - else - forStmt.LoopKind = Statements.ForStatement.Kind.ComplexLoop; + forLoopKind = Kind.NormalLoop; PushScope(forLoopScope); - forStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); - forStmt.LoopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); + var loopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label + List forLoopBody = new List(); for (int i = 0; i < TC.Config.MaxStatementCount; ++i) { StmtKind cur; @@ -449,30 +442,32 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { cur = GetASTUtils().GetRandomTerminalStatement(); } - forStmt.AddToBody(StatementHelper(cur, depth + 1)); + forLoopBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => forStmt.LogVariable(variableName)); // pop for-loop scope + //TODO: This can just append to forLoopBody + PopScope(variableName => LogVariable(forLoopBody, variableName)); // pop 'for-loop' body scope - return Annotate(Block(forStmt.Generate(false)), "for-loop", depth); + return new ForStatement(TC, loopVar, nestNum, numOfSecondaryVars, bounds, forLoopBody, loopStep, forLoopKind); } case StmtKind.DoWhileStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); - DoWhileStatement doStmt = new DoWhileStatement(TC); - doStmt.NestNum = depth; - doStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + var nestNum = depth; + var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); PushScope(doWhileScope); - doStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label + List whileLoopBody = new List(); + for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; @@ -484,29 +479,31 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { cur = GetASTUtils().GetRandomTerminalStatement(); } - doStmt.AddToBody(StatementHelper(cur, depth + 1)); + whileLoopBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => doStmt.LogVariable(variableName)); // pop do-while scope - return Annotate(Block(doStmt.Generate(false)), "do-while", depth); + PopScope(variableName => LogVariable(whileLoopBody, variableName)); // pop 'do-while' body scope + + return new DoWhileStatement(TC, nestNum, numOfSecondaryVars, bounds, whileLoopBody); } case StmtKind.WhileStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); - WhileStatement whileStmt = new WhileStatement(TC); - whileStmt.NestNum = depth; - whileStmt.NumOfSecondaryInductionVariables = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); + var nestNum = depth; + var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); PushScope(whileScope); - whileStmt.Bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack //TODO future: label + List whileLoopBody = new List(); + for (int i = 0; i < PRNG.Next(1, TC.Config.MaxStatementCount); ++i) { StmtKind cur; @@ -518,22 +515,23 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) { cur = GetASTUtils().GetRandomTerminalStatement(); } - whileStmt.AddToBody(StatementHelper(cur, depth + 1)); + whileLoopBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => whileStmt.LogVariable(variableName)); // pop while scope - return Annotate(Block(whileStmt.Generate(false)), "while-loop", depth); + PopScope(variableName => LogVariable(whileLoopBody, variableName)); // pop 'while' body scope + + return new WhileStatement(TC, nestNum, numOfSecondaryVars, bounds, whileLoopBody); } case StmtKind.ReturnStatement: { Tree.ValueType returnType = MethodSignature.ReturnType; if (returnType.PrimitiveType == Primitive.Void) { - return Annotate(ReturnStatement(), "Return", depth); + return new ReturnStatement(TC, null); } - ExpressionSyntax returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, 0); - return Annotate(ReturnStatement(returnExpr), "Return", depth); + Expression returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, 0); + return new ReturnStatement(TC, returnExpr); } case StmtKind.TryCatchFinallyStatement: { @@ -543,7 +541,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) // If there are no catch, then definitely add finally, otherwise skip it. bool hasFinally = catchCounts == 0 || PRNG.Decide(TC.Config.FinallyClauseProbability); - IList tryBody = new List(); + List tryBody = new List(); Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(tryScope); @@ -564,7 +562,8 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(tryBody, variableName)); // pop 'try' body scope - IList catchClauses = new List(); + List>> catchClauses = new (); + var allExceptions = Tree.ValueType.AllExceptions.Select(x => x.Key).ToList(); var caughtExceptions = new List(); @@ -581,7 +580,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) caughtExceptions.Add(exceptionToCatch); int catchStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); - IList catchBody = new List(); + List catchBody = new List(); Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); PushScope(catchScope); @@ -600,11 +599,10 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) catchBody.Add(StatementHelper(cur, depth + 1)); } PopScope(variableName => LogVariable(catchBody, variableName)); // pop 'catch' body scope - - catchClauses.Add(CatchClause(Tree.ValueType.AllExceptions[exceptionToCatch], null, Block(catchBody))); + catchClauses.Add(Tuple.Create(exceptionToCatch, catchBody)); } - IList finallyBody = new List(); + List finallyBody = new List(); if (hasFinally) { Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); @@ -627,7 +625,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) PopScope(variableName => LogVariable(finallyBody, variableName)); // pop 'finally' body scope } - return Annotate(TryStatement(Block(tryBody), catchClauses.ToSyntaxList(), FinallyClause(Block(finallyBody))), "TryCatchFinally", depth); + return new TryCatchFinallyStatement(TC, tryBody, catchClauses, finallyBody); } case StmtKind.SwitchStatement: { @@ -638,8 +636,9 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) Primitive switchType = new Primitive[] { Primitive.Int, Primitive.Long, Primitive.Char, Primitive.String }[PRNG.Next(4)]; Tree.ValueType switchExprType = Tree.ValueType.ForPrimitive(switchType); ExprKind switchExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(switchType); - ExpressionSyntax switchExpr = ExprHelper(switchExprKind, switchExprType, 0); - IList listOfCases = new List(); + Expression switchExpr = ExprHelper(switchExprKind, switchExprType, 0); + //IList listOfCases = new List(); + List>> listOfCases = new (); HashSet usedCaseLabels = new HashSet(); // Generate each cases @@ -650,7 +649,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) // Generate statements within each cases int caseStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); - IList caseBody = new List(); + List caseBody = new List(); for (int j = 0; j < caseStmtCount; j++) { StmtKind cur; @@ -666,17 +665,14 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(caseBody, variableName)); // pop 'case' body scope - caseBody.Add(BreakStatement()); - LiteralExpressionSyntax caseLiteralExpression; + ConstantValue caseConstantValue; do { - caseLiteralExpression = ExprHelper(ExprKind.LiteralExpression, switchExprType, 0) as LiteralExpressionSyntax; - } while (!usedCaseLabels.Add(caseLiteralExpression.Token.ValueText)); + caseConstantValue = ExprHelper(ExprKind.LiteralExpression, switchExprType, 0) as ConstantValue; + } while (!usedCaseLabels.Add(caseConstantValue.Value)); - listOfCases.Add(SwitchSection() - .WithLabels(SingletonList(CaseSwitchLabel(caseLiteralExpression))) - .WithStatements(caseBody.ToSyntaxList())); + listOfCases.Add(Tuple.Create(caseConstantValue, caseBody)); } // Generate default @@ -685,7 +681,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) // Generate statements within default int defaultStmtCount = PRNG.Next(1, 3); - IList defaultBody = new List(); + List defaultBody = new List(); for (int j = 0; j < defaultStmtCount; j++) { StmtKind cur; @@ -701,20 +697,12 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) } PopScope(variableName => LogVariable(defaultBody, variableName)); // pop 'default' body scope - defaultBody.Add(BreakStatement()); - listOfCases.Add( - SwitchSection() - .WithLabels( - SingletonList( - DefaultSwitchLabel())) - .WithStatements(defaultBody.ToSyntaxList())); - - return Annotate(SwitchStatement(switchExpr).WithSections(listOfCases.ToSyntaxList()), "SwitchCase", depth); + return new SwitchStatement(TC, switchExpr, listOfCases, defaultBody); } case StmtKind.MethodCallStatement: { - return Annotate(ExpressionStatement(MethodCallHelper(_testClass.GetRandomMethod(), 0)), "MethodCall", depth); ; + return new MethodCallStatement(TC, MethodCallHelper(_testClass.GetRandomMethod(), 0)); } default: Debug.Assert(false, string.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -731,7 +719,7 @@ public StatementSyntax StatementHelper(StmtKind stmtKind, int depth) /// /// /// - public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int depth) + public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int depth) { //Debug.Assert(depth <= TC.Config.MaxExprDepth); @@ -739,12 +727,12 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i { case ExprKind.LiteralExpression: { - return Annotate(Helpers.GetLiteralExpression(exprType, TC._numerals), "Literal"); + return ConstantValue.GetConstantValue(exprType, TC._numerals); } case ExprKind.VariableExpression: { - return Annotate(TestCase.GetExpressionSyntax(CurrentScope.GetRandomVariable(exprType)), "Var"); + return new VariableExpression(TC, CurrentScope.GetRandomVariable(exprType)); } case ExprKind.BinaryOpExpression: @@ -787,20 +775,13 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i // errors during compiling the test case. if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) { - return Annotate(Helpers.GetWrappedAndCastedExpression(exprType, exprType, Helpers.GetLiteralExpression(exprType, TC._numerals)), "BinOp-folded"); + return ConstantValue.GetConstantValue(exprType, TC._numerals); } - ExpressionSyntax lhs = ExprHelper(lhsExprKind, lhsExprType, depth + 1); - ExpressionSyntax rhs = ExprHelper(rhsExprKind, rhsExprType, depth + 1); + Expression lhs = ExprHelper(lhsExprKind, lhsExprType, depth + 1); + Expression rhs = ExprHelper(rhsExprKind, rhsExprType, depth + 1); - // For division, make sure that divisor is not 0 - if ((op.Oper == SyntaxKind.DivideExpression) || (op.Oper == SyntaxKind.ModuloExpression)) - { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, exprType, rhs); - } - - return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, Helpers.GetBinaryExpression(lhs, op, rhs)), "BinOp"); + return new CastExpression(TC, new BinaryExpression(TC, lhs, op, rhs), exprType); } case ExprKind.AssignExpression: { @@ -826,18 +807,10 @@ public ExpressionSyntax ExprHelper(ExprKind exprKind, Tree.ValueType exprType, i rhsKind = GetRandomTerminalExpression(rhsExprType); } - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); - ExpressionSyntax rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); - - // For division, make sure that divisor is not 0 - if ((assignOper.Oper == SyntaxKind.DivideAssignmentExpression) || (assignOper.Oper == SyntaxKind.ModuloAssignmentExpression)) - { - rhs = ParenthesizedExpression(BinaryExpression(SyntaxKind.AddExpression, ParenthesizedExpression(rhs), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10, 100))))); - rhs = Helpers.GetWrappedAndCastedExpression(rhsExprType, lhsExprType, rhs); - } + Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); + Expression rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); - return Annotate(Helpers.GetWrappedAndCastedExpression(lhsExprType, exprType, - AssignmentExpression(assignOper.Oper, lhs, rhs)), "Assign"); + return new CastExpression(TC, new AssignExpression(TC, lhs, assignOper, rhs), exprType); } case ExprKind.MethodCallExpression: { @@ -950,9 +923,11 @@ private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) return kind; } - private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) + private Expression MethodCallHelper(MethodSignature methodSig, int depth) { - List argumentNodes = new List(); + List argumentNodes = new List(); + List passingWays = new List(); + int paramsCount = methodSig.Parameters.Count; for (int paramId = 0; paramId < paramsCount; paramId++) @@ -978,27 +953,13 @@ private ExpressionSyntax MethodCallHelper(MethodSignature methodSig, int depth) argExprKind = ExprKind.VariableExpression; } - ExpressionSyntax argExpr = ExprHelper(argExprKind, argType, depth + 1); - ArgumentSyntax argSyntax = Argument(argExpr); - - if (parameter.PassingWay == ParamValuePassing.Ref) - { - argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.RefKeyword)); - } - else if (parameter.PassingWay == ParamValuePassing.Out) - { - argSyntax = argSyntax.WithRefKindKeyword(Token(SyntaxKind.OutKeyword)); - } + Expression argExpr = ExprHelper(argExprKind, argType, depth + 1); - argumentNodes.Add(argSyntax); - if (paramId + 1 < paramsCount) - { - argumentNodes.Add(Token(SyntaxKind.CommaToken)); - } + passingWays.Add(parameter.PassingWay); + argumentNodes.Add(argExpr); } - return InvocationExpression(IdentifierName(methodSig.MethodName)) - .WithArgumentList(ArgumentList(SeparatedList(argumentNodes))); + return new MethodCallExpression(methodSig.MethodName, argumentNodes, passingWays); } private Tree.ValueType GetRandomExprType() diff --git a/Tree/Node.cs b/Tree/Node.cs index cfac76e..c19253d 100644 --- a/Tree/Node.cs +++ b/Tree/Node.cs @@ -10,20 +10,25 @@ namespace Antigen.Tree { - public class Node + public abstract class Node { protected TestCase _testCase; + protected string _contents; //public virtual void Render(RenderContext renderContext) //{ //} + //TODO: Have this call an abstract method public override string ToString() { - return string.Empty; // base.ToString(); + return Annotate(); } + protected abstract string Annotate(); + protected virtual void PopulateContent() { } + public Node(TestCase tc) { _testCase = tc; From cf19fe483346cbc49d2b7853b3e53e2fd96fad4e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 11 Sep 2021 01:15:14 -0700 Subject: [PATCH 071/149] Working less memory model --- Config/antigen.json | 8 +- Expressions/AssignExpression.cs | 2 +- Expressions/BinaryExpression.cs | 21 +- Expressions/ConstantValue.cs | 22 ++- Expressions/Expression.cs | 7 +- Expressions/MethodCallExpression.cs | 12 +- Helpers/PreGenerated.cs | 98 +++++----- Helpers/TestRunner.cs | 6 +- Statements/DoWhileStatement.cs | 10 +- Statements/ForStatement.cs | 12 +- Statements/IfElseStatement.cs | 13 +- Statements/LoopStatement.cs | 12 +- Statements/MethodCallStatement.cs | 1 + Statements/Statement.cs | 16 +- Statements/SwitchStatement.cs | 16 +- Statements/TryCatchFinallyStatement.cs | 13 +- Statements/VarDeclStatement.cs | 2 +- Statements/WhileStatement.cs | 7 +- Structs.cs | 20 -- TestCase.cs | 22 ++- TestClass.cs | 103 ++++------ TestMethod.cs | 253 ++++++++++--------------- Tree/Node.cs | 12 +- Tree/Scope.cs | 50 +++-- Tree/Types.cs | 70 +++---- Trimmer/TestTrimmer.cs | 6 +- 26 files changed, 361 insertions(+), 453 deletions(-) diff --git a/Config/antigen.json b/Config/antigen.json index 1ecc841..ea0d8b0 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,5 +1,5 @@ { - "Seed": -1, + "Seed": 1, "OutputDirectory": ".", "NumTestCases": 1000, "HoursToRun": 10, @@ -639,9 +639,9 @@ }, { "Name": "Structs", - "StructCount": 10, - "StructFieldCount": 10, - "NestedStructDepth": 5, + "StructCount": 5, + "StructFieldCount": 5, + "NestedStructDepth": 3, "NestedStructProbability": 0.4, "StructFieldTypeProbability": 0.5, "StructAliasProbability": 0.5, diff --git a/Expressions/AssignExpression.cs b/Expressions/AssignExpression.cs index 360c7e3..8d21655 100644 --- a/Expressions/AssignExpression.cs +++ b/Expressions/AssignExpression.cs @@ -14,7 +14,7 @@ namespace Antigen.Expressions { public class AssignExpression : BinaryExpression { - public AssignExpression(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase, lhs, op, rhs) + public AssignExpression(TestCase testCase, Tree.ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase, leftType, lhs, op, rhs) { } } diff --git a/Expressions/BinaryExpression.cs b/Expressions/BinaryExpression.cs index 7a5706f..ca92492 100644 --- a/Expressions/BinaryExpression.cs +++ b/Expressions/BinaryExpression.cs @@ -18,7 +18,7 @@ public class BinaryExpression : Expression public readonly Operator Op; public readonly Expression Right; - public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase) + public BinaryExpression(TestCase testCase, Tree.ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase) { Left = lhs; Op = op; @@ -30,9 +30,14 @@ public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expressi (Op.Oper == SyntaxKind.ModuloExpression)) { // To avoid divide by zero errors - Right = new AssignExpression(testCase, + var addExpression = new AssignExpression( + testCase, + leftType, new ParenthsizedExpression(testCase, rhs), - Operator.ForSyntaxKind(SyntaxKind.AddExpression), ConstantValue.GetRandomConstantInt()); + Operator.ForSyntaxKind(SyntaxKind.AddExpression), + ConstantValue.GetRandomConstantInt(10, 100)); + + Right = new CastExpression(testCase, addExpression, leftType); } else { @@ -40,16 +45,6 @@ public BinaryExpression(TestCase testCase, Expression lhs, Operator op, Expressi } } - protected override string GetCode() - { - return base.GetCode(); - } - - protected override void PopulateContent() - { - base.PopulateContent(); - } - public override string ToString() { return $"{Left} {Op} {Right}"; diff --git a/Expressions/ConstantValue.cs b/Expressions/ConstantValue.cs index 447e814..495c98c 100644 --- a/Expressions/ConstantValue.cs +++ b/Expressions/ConstantValue.cs @@ -20,14 +20,28 @@ protected ConstantValue(Tree.ValueType valueType, string value) : base(null) { if (valueType.PrimitiveType == Primitive.Char) { - Value = $"'{Value}'"; + Value = $"'{value}'"; return; } else if (valueType.PrimitiveType == Primitive.String) { - Value = $"\"{Value}\""; + Value = $"\"{value}\""; return; } + else if (valueType.PrimitiveType == Primitive.Float) + { + Value = $"{value}f"; + return; + } + else if (valueType.PrimitiveType == Primitive.Decimal) + { + Value = $"{value}m"; + return; + } + else if ((valueType.PrimitiveType & Primitive.UnsignedInteger) != 0) + { + value = value.TrimStart('-'); + } else if (valueType.PrimitiveType == Primitive.Boolean) { Debug.Assert(value == "false" || value == "true"); @@ -40,9 +54,9 @@ public override string ToString() return $"{Value}"; } - public static ConstantValue GetRandomConstantInt() + public static ConstantValue GetRandomConstantInt(int min, int max) { - return new ConstantValue(Tree.ValueType.ForPrimitive(Primitive.Int), PRNG.Next(10, 100).ToString()); + return new ConstantValue(Tree.ValueType.ForPrimitive(Primitive.Int), PRNG.Next(min, max).ToString()); } public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList> numerals) diff --git a/Expressions/Expression.cs b/Expressions/Expression.cs index cea374f..e833433 100644 --- a/Expressions/Expression.cs +++ b/Expressions/Expression.cs @@ -1,10 +1,11 @@ -using Antigen.Tree; +using System.Collections.Generic; +using Antigen.Tree; namespace Antigen.Expressions { public class Expression : Node { -#if DEBUG +#if DEBUG_TODO private readonly Dictionary _expressionsCount = new(); #endif @@ -15,7 +16,7 @@ public Expression(TestCase testCase) : base(testCase) protected override string Annotate() { -#if DEBUG +#if DEBUG_TODO string typeName = GetType().Name; if (!_expressionsCount.ContainsKey(typeName)) { diff --git a/Expressions/MethodCallExpression.cs b/Expressions/MethodCallExpression.cs index 654e80f..05fa17f 100644 --- a/Expressions/MethodCallExpression.cs +++ b/Expressions/MethodCallExpression.cs @@ -23,11 +23,10 @@ public MethodCallExpression(string methodName, List arguments, List< MethodName = methodName; Arguments = arguments; - - PopulateContent(); + ArgsPassingWays = passingWays; } - protected override void PopulateContent() + public override string ToString() { List finalArgs = new List(); @@ -52,12 +51,7 @@ protected override void PopulateContent() } } - _contents = $"{MethodName}({string.Join(", ", finalArgs)})"; - } - - public override string ToString() - { - return _contents; + return $"{MethodName}({string.Join(", ", finalArgs)})"; } } } diff --git a/Helpers/PreGenerated.cs b/Helpers/PreGenerated.cs index 25ebe85..507ae51 100644 --- a/Helpers/PreGenerated.cs +++ b/Helpers/PreGenerated.cs @@ -10,78 +10,76 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - +using Antigen.Statements; namespace Antigen { public static class PreGenerated { + private static ArbitraryCodeStatement s_usingStmts = null; /// /// Returns code related to using directives. /// - public static List UsingDirective = - new List() + public static Statement UsingDirective + { + get { - UsingDirective(IdentifierName("System")) - .WithUsingKeyword(Token(TriviaList(new[]{ - Comment("// Licensed to the .NET Foundation under one or more agreements."), - Comment("// The .NET Foundation licenses this file to you under the MIT license."), - Comment("// See the LICENSE file in the project root for more information."), - Comment("//"), - Comment("// This file is auto-generated."), - Comment("// Seed: " + PRNG.GetSeed()), - Comment("//"), - }), SyntaxKind.UsingKeyword, TriviaList())), - UsingDirective( - QualifiedName( - QualifiedName( - IdentifierName("System"), - IdentifierName("Collections")), - IdentifierName("Generic"))), - UsingDirective( - QualifiedName( - QualifiedName( - IdentifierName("System"), - IdentifierName("Runtime")), - IdentifierName("CompilerServices"))) - }; + if (s_usingStmts != null) + { + return s_usingStmts; + } + string usingCode = +@"// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// This file is auto-generated. +// Seed: -1 +// + using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +"; + s_usingStmts = new ArbitraryCodeStatement(null, usingCode); + return s_usingStmts; + } + } - private static List staticMethods = null; + private static ArbitraryCodeStatement s_staticMethods = null; /// /// Returns list of 3 static methods - Main, Log and PrintLog. /// - public static List StaticMethods + public static Statement StaticMethods { get { - if (staticMethods != null) + if (s_staticMethods != null) { - return staticMethods; + return s_staticMethods; } - MethodDeclarationSyntax mainMethod = (MethodDeclarationSyntax)ParseMemberDeclaration(@$"public static void Main(string[] args) {{ }}"); - MethodDeclarationSyntax loggerMethod = (MethodDeclarationSyntax)ParseMemberDeclaration( - $@"[MethodImpl(MethodImplOptions.NoInlining)] -public static void Log(string varName, object varValue) {{ - toPrint.Add($""{{varName}}={{varValue}}""); -}}"); - MethodDeclarationSyntax printLogMethod = (MethodDeclarationSyntax)ParseMemberDeclaration( - $@" -public static void PrintLog() {{ - foreach (var entry in toPrint) - {{ - Console.WriteLine(entry); - }} -}} -"); + StringBuilder staticMethodBuilder = new StringBuilder(); - staticMethods = new List() - { - mainMethod, loggerMethod, printLogMethod - }; - return staticMethods; + // Main method + staticMethodBuilder.AppendLine("public static void Main(string[] args) { }"); + + // Log method + staticMethodBuilder.AppendLine("[MethodImpl(MethodImplOptions.NoInlining)]"); + staticMethodBuilder.AppendLine("public static void Log(string varName, object varValue) {"); + staticMethodBuilder.AppendLine(@$" toPrint.Add($""{{varName}}={{varValue}}"");"); + staticMethodBuilder.AppendLine("}"); + + // PrintLog method + staticMethodBuilder.AppendLine("public static void PrintLog() {"); + staticMethodBuilder.AppendLine("foreach (var entry in toPrint) {"); + staticMethodBuilder.AppendLine("Console.WriteLine(entry);"); + staticMethodBuilder.AppendLine("}}"); + + s_staticMethods = new ArbitraryCodeStatement(null, staticMethodBuilder.ToString()); + + return s_staticMethods; } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index 926f398..a7d0885 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -79,9 +79,9 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) #endif } - ms.Seek(0, SeekOrigin.Begin); - File.WriteAllBytes(assemblyFullPath, ms.ToArray()); - Console.WriteLine($"{ms.Length} bytes"); + //ms.Seek(0, SeekOrigin.Begin); + //File.WriteAllBytes(assemblyFullPath, ms.ToArray()); + //Console.WriteLine($"{ms.Length} bytes"); return new CompileResult(assemblyName, assemblyFullPath); } diff --git a/Statements/DoWhileStatement.cs b/Statements/DoWhileStatement.cs index 678d9bd..8f544f5 100644 --- a/Statements/DoWhileStatement.cs +++ b/Statements/DoWhileStatement.cs @@ -15,14 +15,12 @@ public class DoWhileStatement : LoopStatement public DoWhileStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : base(tc, nestNum, numOfSecondaryVars, bounds, loopBody) { - PopulateContent(); } protected override void PopulatePreLoopBody() { // Induction variables to be initialized outside the loop - loopBodyBuilder.AppendLine(GenerateIVInitCode()); - + loopBodyBuilder.AppendFormat("{0};", GenerateIVInitCode()).AppendLine(); loopBodyBuilder.AppendLine("do {"); // Add step/break condition at the beginning @@ -35,13 +33,13 @@ protected override void PopulatePostLoopBody() loopBodyBuilder.AppendLine(string.Join(Environment.NewLine, GenerateIVBreakAndStepCode(isCodeForBreakCondAtTheEnd: true))); loopBodyBuilder.AppendLine("} while("); - loopBodyBuilder.Append($"({Bounds})"); + loopBodyBuilder.AppendFormat("({0})", Bounds); string loopGuardCondition = GenerateIVLoopGuardCode(); if (!string.IsNullOrEmpty(loopGuardCondition)) - loopBodyBuilder.Append($" && ({loopGuardCondition})"); + loopBodyBuilder.AppendFormat(" && ({0})", loopGuardCondition); - loopBodyBuilder.AppendLine("');"); + loopBodyBuilder.AppendLine(");"); Debug.Assert(HasSuccessfullyGenerated(), "DoWhileStatement didn't generate properly. Please check the loop variables."); } diff --git a/Statements/ForStatement.cs b/Statements/ForStatement.cs index 2cf7ce6..664dd97 100644 --- a/Statements/ForStatement.cs +++ b/Statements/ForStatement.cs @@ -31,19 +31,15 @@ public ForStatement( LoopVar = loopVar; LoopStep = loopStep; LoopKind = loopKind; - - loopBodyBuilder = new StringBuilder(); - - PopulateContent(); } protected override void PopulatePreLoopBody() { // Induction variables to be initialized outside the loop - loopBodyBuilder.AppendLine(GenerateIVInitCode(false)); + loopBodyBuilder.AppendFormat("{0};", GenerateIVInitCode(false)).AppendLine(); // induction variable initialization - loopBodyBuilder.Append($"for({GenerateIVInitCode(true)};"); + loopBodyBuilder.AppendFormat("for({0};", GenerateIVInitCode(true)); // condition string guardCode = GenerateIVLoopGuardCode(); @@ -53,7 +49,7 @@ protected override void PopulatePreLoopBody() { if (!string.IsNullOrEmpty(guardCode)) loopBodyBuilder.Append(" &&"); - loopBodyBuilder.Append($" {LoopVar} < ({Bounds})"); + loopBodyBuilder.AppendFormat(" {0} < ({1})", LoopVar, Bounds); } loopBodyBuilder.Append(';'); @@ -67,7 +63,7 @@ protected override void PopulatePreLoopBody() { loopBodyBuilder.Append(" ,"); } - loopBodyBuilder.Append($" {LoopVar}++"); + loopBodyBuilder.AppendFormat(" {0}++", LoopVar); } else if (LoopKind == Kind.ComplexLoop) { diff --git a/Statements/IfElseStatement.cs b/Statements/IfElseStatement.cs index 7c19416..7bf51eb 100644 --- a/Statements/IfElseStatement.cs +++ b/Statements/IfElseStatement.cs @@ -22,14 +22,12 @@ public IfElseStatement(TestCase testCase, Expression condition, List Condition = condition; IfBody = ifBody; ElseBody = elseBody; - - PopulateContent(); } - protected override void PopulateContent() + public override string ToString() { StringBuilder strBuilder = new StringBuilder(); - strBuilder.AppendLine($"if ({Condition})"); + strBuilder.AppendFormat("if ({0})", Condition).AppendLine(); strBuilder.AppendLine("{"); strBuilder.AppendLine(string.Join(Environment.NewLine, IfBody)); strBuilder.AppendLine("}"); @@ -40,12 +38,7 @@ protected override void PopulateContent() strBuilder.AppendLine(string.Join(Environment.NewLine, ElseBody)); strBuilder.AppendLine("}"); } - _contents = strBuilder.ToString(); - } - - public override string ToString() - { - return _contents; + return strBuilder.ToString(); } } } diff --git a/Statements/LoopStatement.cs b/Statements/LoopStatement.cs index 25a2bbb..ea0a153 100644 --- a/Statements/LoopStatement.cs +++ b/Statements/LoopStatement.cs @@ -235,11 +235,11 @@ internal string GetLoopStep() { if (LoopParameters.LoopInductionChangeFactor == 1) { - return Name + (LoopParameters.IsForwardLoop ? "++" : "--") + ";"; + return Name + (LoopParameters.IsForwardLoop ? "++" : "--"); } else { - return string.Format("{0} {1}= {2};", Name, LoopParameters.IsForwardLoop ? "+" : "-", LoopParameters.LoopInductionChangeFactor); + return string.Format("{0} {1}= {2}", Name, LoopParameters.IsForwardLoop ? "+" : "-", LoopParameters.LoopInductionChangeFactor); } } @@ -335,7 +335,7 @@ public class LoopStatement : Statement private int _nestNum; private int _noOfSecondaryInductionVariables; private List _inductionVariables; - protected StringBuilder loopBodyBuilder = new StringBuilder(); + protected StringBuilder loopBodyBuilder; #region Properties @@ -516,7 +516,7 @@ public LoopStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expressio Body = loopBody; } - protected override void PopulateContent() + public override string ToString() { loopBodyBuilder = new StringBuilder(); @@ -524,7 +524,7 @@ protected override void PopulateContent() PopulateLoopBody(); PopulatePostLoopBody(); - _contents = loopBodyBuilder.ToString(); + return loopBodyBuilder.ToString(); } public string GetImplicitLoopVar() @@ -601,7 +601,7 @@ protected string GenerateIVInitCode(bool isInitLoopHead = false) } if (loopInits.Count > 0) { - return $"int {string.Join(",", loopInits)};"; + return $"int {string.Join(",", loopInits)}"; } return string.Empty; diff --git a/Statements/MethodCallStatement.cs b/Statements/MethodCallStatement.cs index 97beb45..b30ebc1 100644 --- a/Statements/MethodCallStatement.cs +++ b/Statements/MethodCallStatement.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; namespace Antigen.Statements { diff --git a/Statements/Statement.cs b/Statements/Statement.cs index 803219e..ca861a0 100644 --- a/Statements/Statement.cs +++ b/Statements/Statement.cs @@ -1,11 +1,12 @@ -using Antigen.Tree; +using System.Collections.Generic; +using Antigen.Tree; namespace Antigen.Statements { public class Statement : Node { -#if DEBUG +#if DEBUG_TODO private readonly Dictionary _statementsCount = new(); #endif @@ -17,22 +18,17 @@ public Statement(TestCase testCase) : base(testCase) protected override string Annotate() { -#if DEBUG +#if DEBUG_TODO string typeName = GetType().Name; if (!_statementsCount.ContainsKey(typeName)) { _statementsCount[typeName] = 0; } _statementsCount[typeName]++; - return $"{GetCode() /* S#{_statementsCount[typeName]}: {typeName} */}"; + return $"{ToString() /* S#{_statementsCount[typeName]}: {typeName} */}"; #else - return GetCode(); + return ToString(); #endif } - - protected override string GetCode() - { - return string.Empty; - } } } diff --git a/Statements/SwitchStatement.cs b/Statements/SwitchStatement.cs index 1a35bd4..16f52b3 100644 --- a/Statements/SwitchStatement.cs +++ b/Statements/SwitchStatement.cs @@ -23,26 +23,19 @@ public SwitchStatement(TestCase testCase, SwitchExpr = switchExpr; Cases = cases; DefaultBody = defaultBody; - - PopulateContent(); } public override string ToString() - { - return _contents; - } - - protected override void PopulateContent() { StringBuilder strBuilder = new StringBuilder(); - strBuilder.AppendLine($"switch ({SwitchExpr})"); + strBuilder.AppendFormat("switch ({0})", SwitchExpr).AppendLine(); strBuilder.AppendLine("{"); if (Cases != null && Cases.Count > 0) { foreach (var caseClause in Cases) { - strBuilder.AppendLine($"case {caseClause.Item1}:"); + strBuilder.AppendFormat("case {0}:", caseClause.Item1).AppendLine(); strBuilder.AppendLine("{"); strBuilder.AppendLine(string.Join(Environment.NewLine, caseClause.Item2)); strBuilder.AppendLine("break;"); @@ -50,15 +43,14 @@ protected override void PopulateContent() } } - strBuilder.AppendLine($"default:"); + strBuilder.AppendLine("default:"); strBuilder.AppendLine("{"); strBuilder.AppendLine(string.Join(Environment.NewLine, DefaultBody)); strBuilder.AppendLine("break;"); strBuilder.AppendLine("}"); strBuilder.AppendLine("}"); - - _contents = strBuilder.ToString(); + return strBuilder.ToString(); } } } diff --git a/Statements/TryCatchFinallyStatement.cs b/Statements/TryCatchFinallyStatement.cs index 850637a..837a8d6 100644 --- a/Statements/TryCatchFinallyStatement.cs +++ b/Statements/TryCatchFinallyStatement.cs @@ -22,16 +22,9 @@ public TryCatchFinallyStatement(TestCase testCase, TryBody = tryBody; CatchBodies = catchBodies; FinallyBody = finallyBody; - - PopulateContent(); } public override string ToString() - { - return _contents; - } - - protected override void PopulateContent() { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendLine("try"); @@ -42,7 +35,7 @@ protected override void PopulateContent() { foreach (var catchClause in CatchBodies) { - strBuilder.AppendLine($"catch ({catchClause.Item1})"); + strBuilder.AppendFormat("catch ({0})", catchClause.Item1).AppendLine(); strBuilder.AppendLine("{"); strBuilder.AppendLine(string.Join(Environment.NewLine, catchClause.Item2)); strBuilder.AppendLine("}"); @@ -50,12 +43,12 @@ protected override void PopulateContent() } if (FinallyBody != null && FinallyBody.Count > 0) { - strBuilder.AppendLine($"finally"); + strBuilder.AppendLine("finally"); strBuilder.AppendLine("{"); strBuilder.AppendLine(string.Join(Environment.NewLine, FinallyBody)); strBuilder.AppendLine("}"); } - _contents = strBuilder.ToString(); + return strBuilder.ToString(); } } } diff --git a/Statements/VarDeclStatement.cs b/Statements/VarDeclStatement.cs index 2ea4268..63dc3c6 100644 --- a/Statements/VarDeclStatement.cs +++ b/Statements/VarDeclStatement.cs @@ -26,7 +26,7 @@ public VarDeclStatement(TestCase testCase, Tree.ValueType typeName, string varia public override string ToString() { - return $"{TypeName} {VariableName} = {Expression};"; + return Expression != null ? $"{TypeName} {VariableName} = {Expression};" : $"{TypeName} {VariableName};"; } } } diff --git a/Statements/WhileStatement.cs b/Statements/WhileStatement.cs index 84342f4..13684b4 100644 --- a/Statements/WhileStatement.cs +++ b/Statements/WhileStatement.cs @@ -15,20 +15,19 @@ public class WhileStatement : LoopStatement public WhileStatement(TestCase tc, int nestNum, int numOfSecondaryVars, Expression bounds, List loopBody) : base(tc, nestNum, numOfSecondaryVars, bounds, loopBody) { - PopulateContent(); } protected override void PopulatePreLoopBody() { // Induction variables to be initialized outside the loop - loopBodyBuilder.AppendLine(GenerateIVInitCode()); + loopBodyBuilder.AppendFormat("{0};", GenerateIVInitCode()).AppendLine(); loopBodyBuilder.Append("while("); - loopBodyBuilder.Append($"({Bounds})"); + loopBodyBuilder.AppendFormat("({0})", Bounds); string loopGuardCondition = GenerateIVLoopGuardCode(); if (!string.IsNullOrEmpty(loopGuardCondition)) - loopBodyBuilder.Append($" && ({loopGuardCondition})"); + loopBodyBuilder.AppendFormat(" && ({0})", loopGuardCondition); loopBodyBuilder.Append(')'); loopBodyBuilder.AppendLine("{"); diff --git a/Structs.cs b/Structs.cs index 0ed2edc..f0454ee 100644 --- a/Structs.cs +++ b/Structs.cs @@ -11,25 +11,5 @@ namespace Antigen { - /// - /// Represents a field present in a struct. This is useful to - /// expand the fully qualifier name of a field present inside a - /// nested struct. - /// - public struct StructField - { - public string FieldName; - public Tree.ValueType FieldType; - public StructField(Tree.ValueType type, string name) - { - FieldType = type; - FieldName = name; - } - - public override string ToString() - { - return $"{Enum.GetName(typeof(Primitive), FieldType.PrimitiveType)} {FieldName}"; - } - } } diff --git a/TestCase.cs b/TestCase.cs index 593d5f1..01e01cf 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -1,4 +1,5 @@ using Antigen.Config; +using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -115,11 +116,18 @@ public TestCase(int testId, RunOptions runOptions) public void Generate() { - ClassDeclarationSyntax klass = new TestClass(this, Name).Generate(); + var klass = new TestClass(this, Name).Generate(); + var finalCode = PreGenerated.UsingDirective + klass.ToString(); - testCaseRoot = CompilationUnit() - .WithUsings(PreGenerated.UsingDirective.ToSyntaxList()) - .WithMembers(new SyntaxList(klass)); + testCaseRoot = CSharpSyntaxTree.ParseText(finalCode).GetRoot(); + + //string formattedContents = testCaseRoot.NormalizeWhitespace().SyntaxTree.GetText().ToString(); + + File.WriteAllText(@"e:\perfinvestigation\minibench\Antigen.cs", finalCode); + //File.WriteAllText(@"e:\perfinvestigation\minibench\Antigen.cs", testCaseRoot.ToFullString()); + //var _1 = CSharpSyntaxTree.ParseText(finalCode).GetRoot(); + //var _2 = CSharpSyntaxTree.ParseText(CSharpSyntaxTree.ParseText(finalCode).GetRoot().ToFullString()); + Console.WriteLine(); } public TestResult Verify() @@ -284,7 +292,7 @@ private void SaveTestCase( fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); fileContents.AppendLine("/*"); - fileContents.AppendLine($"Config: {Config.Name}"); + fileContents.AppendFormat("Config: {0}", Config.Name).AppendLine(); fileContents.AppendLine("--------- Baseline ---------"); fileContents.AppendLine(); fileContents.AppendLine("Environment:"); @@ -293,7 +301,7 @@ private void SaveTestCase( { foreach (var envVars in baselineVars) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); } } fileContents.AppendLine(); @@ -307,7 +315,7 @@ private void SaveTestCase( { foreach (var envVars in testVars) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); } } fileContents.AppendLine(); diff --git a/TestClass.cs b/TestClass.cs index a90b0ca..5f55211 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Antigen.Expressions; +using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -113,47 +115,49 @@ public Scope PopScope() return ret; } - public ClassDeclarationSyntax Generate() + public ClassDeclStatement Generate() { // push class scope PushScope(ClassScope); - List classMembers = new List(); + List classMembers = new List(); classMembers.AddRange(GenerateStructs()); - classMembers.AddRange(GenerateStaticFields()); + classMembers.AddRange(GenerateFields(isStatic: true)); + classMembers.AddRange(GenerateFields(isStatic: false)); + + // special + classMembers.Add(new FieldDeclStatement(TC, Tree.ValueType.ForPrimitive(Primitive.Int), Constants.LoopInvariantName, ConstantValue.GetRandomConstantInt(0, 10), true)); + classMembers.Add(new ArbitraryCodeStatement(TC, "private static List toPrint = new List();")); + classMembers.AddRange(GenerateLeafMethods()); classMembers.AddRange(GenerateMethods()); + classMembers.Add(PreGenerated.StaticMethods); // pop class scope PopScope(); - return ClassDeclaration(ClassName) - .WithMembers(classMembers.ToSyntaxList()) - .WithModifiers(new SyntaxTokenList(Token(SyntaxKind.PublicKeyword))); + return new ClassDeclStatement(TC, ClassName, classMembers); } /// /// Generate structs in this class /// /// - private List GenerateStructs() + private List GenerateStructs() { - List structs = new List(); + List structs = new List(); for (int structIndex = 1; structIndex <= TC.Config.StructCount; structIndex++) { string structName = $"S{structIndex}"; - var (structDecl, fields) = GenerateStruct(structName, structName, structIndex, 1); + var structDecl = GenerateStruct(structName, structName, structIndex, 1); structs.Add(structDecl); - CurrentScope.AddStructType(structName, fields); + CurrentScope.AddStructType(structName, structDecl.StructFields); } - (MemberDeclarationSyntax, List) GenerateStruct(string structName, string structType, int structIndex, int depth) + StructDeclStatement GenerateStruct(string structName, string structType, int structIndex, int depth) { - StructDeclarationSyntax structDeclaration = StructDeclaration(structName) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); - - List fieldsTree = new List(); + List nestedStructs = new List(); List fieldsMetadata = new List(); int fieldCount = PRNG.Next(1, TC.Config.StructFieldCount); for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) @@ -162,10 +166,11 @@ private List GenerateStructs() { string nestedStructName = $"S{structIndex}_D{depth}_F{fieldIndex}"; string nestedStructType = structType + "." + nestedStructName; - var (structDecl, childFields) = GenerateStruct(nestedStructName, nestedStructType, structIndex, depth + 1); - fieldsTree.Add(structDecl); - CurrentScope.AddStructType(nestedStructType, childFields); - structName = nestedStructName; + var structDecl = GenerateStruct(nestedStructName, nestedStructType, structIndex, depth + 1); + nestedStructs.Add(structDecl); + CurrentScope.AddStructType(nestedStructType, structDecl.StructFields); + + //structName = nestedStructName; continue; } @@ -182,11 +187,10 @@ private List GenerateStructs() } fieldName = Helpers.GetVariableName(fieldType, fieldIndex); - fieldsTree.Add(FieldDeclaration(Helpers.GetVariableDeclaration(fieldType, fieldName)).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); + //fieldsTree.Add(new VarDeclStatement(TC, fieldType, fieldName, null)); fieldsMetadata.Add(new StructField(fieldType, fieldName)); } - - return (structDeclaration.WithMembers(fieldsTree.ToSyntaxList()), fieldsMetadata); + return new StructDeclStatement(TC, structName, fieldsMetadata, nestedStructs); } return structs; @@ -196,9 +200,9 @@ private List GenerateStructs() /// Generate methods in this class /// /// - private IList GenerateMethods() + private IList GenerateMethods() { - List methods = new List(); + List methods = new List(); for (int i = 1; i < TC.Config.MethodCount; i++) { @@ -207,32 +211,15 @@ private IList GenerateMethods() } methods.Add(new TestMethod(this, "Method0", true).Generate()); - var staticMethods = PreGenerated.StaticMethods; - var mainMethod = staticMethods[0]; - var loggerMethod = staticMethods[1]; - var printLogMethod = staticMethods[2]; - - mainMethod = mainMethod.WithBody( - Block( - ParseStatement($"{ClassName} obj{ClassName} = new {ClassName}();"), - ParseStatement($"obj{ClassName}.Method0();"), - ParseStatement("PrintLog();") - ) - ); - - methods.Add(mainMethod); - methods.Add(loggerMethod); - methods.Add(printLogMethod); - return methods; } /// /// Generate leaf methods in this class. /// - private IList GenerateLeafMethods() + private IList GenerateLeafMethods() { - List leafMethods = new List(); + List leafMethods = new List(); int leafMethodId = 0; foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { @@ -249,31 +236,31 @@ private IList GenerateLeafMethods() } /// - /// Generate static fields in this class. + /// Generate fields in this class. /// - private IList GenerateStaticFields() + private List GenerateFields(bool isStatic) { - List fields = new List(); + List fields = new List(); // TODO-TEMP initialize one variable of each type int _variablesCount = 0; foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { - string variableName = "s_" + Helpers.GetVariableName(variableType, _variablesCount++); + string variableName = (isStatic ? "s_" : string.Empty) + Helpers.GetVariableName(variableType, _variablesCount++); + + Expression rhs = ConstantValue.GetConstantValue(variableType, TC._numerals); - ExpressionSyntax rhs = Helpers.GetLiteralExpression(variableType, TC._numerals); CurrentScope.AddLocal(variableType, variableName); - fields.Add(FieldDeclaration(Helpers.GetVariableDeclaration(variableType, variableName, rhs)) - .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + fields.Add(new FieldDeclStatement(TC, variableType, variableName, rhs, isStatic)); } // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { - string variableName = "s_" + Helpers.GetVariableName(structType, _variablesCount++); + string variableName = (isStatic ? "s_" : string.Empty) + Helpers.GetVariableName(structType, _variablesCount++); - ExpressionSyntax rhs = Helpers.GetObjectCreationExpression(structType.TypeName); + Expression rhs = new CreationExpression(TC, structType.TypeName, null); CurrentScope.AddLocal(structType, variableName); // Add all the fields to the scope @@ -283,20 +270,10 @@ private IList GenerateStaticFields() CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); } - fields.Add(FieldDeclaration(Helpers.GetVariableDeclaration(structType, variableName, rhs)) - .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); + fields.Add(new FieldDeclStatement(TC, structType, variableName, rhs, isStatic)); } //TODO: Define some more constants - fields.Add( - FieldDeclaration( - Helpers.GetVariableDeclaration( - Tree.ValueType.ForPrimitive(Primitive.Int), - Constants.LoopInvariantName, - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(PRNG.Next(10))))) - .WithModifiers(TokenList(Token(SyntaxKind.StaticKeyword)))); - - fields.Add(PreGenerated.LoggerVariableDecl); return fields; } diff --git a/TestMethod.cs b/TestMethod.cs index ef3dbf3..31ab440 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen @@ -20,7 +21,7 @@ namespace Antigen public class TestMethod { private readonly TestClass _testClass; - private TestCase TC => _testClass.TC; + protected TestCase TC => _testClass.TC; protected readonly string Name; private readonly List> _valuePassing; @@ -31,6 +32,7 @@ public class TestMethod #endif private int _variablesCount = 0; + private int _loopVarCount = 0; internal HashSet callsFromThisMethod = new HashSet(); @@ -49,25 +51,9 @@ protected void PushScope(Scope scope) _testClass.PushScope(scope); } - protected Scope PopScope(Action trackLocalVariables) + protected Scope PopScope() { - Scope ret = _testClass.PopScope(); - - // Before poping, log the variables - foreach (var variableName in ret.AllVariables) - { - if (PRNG.Decide(TC.Config.LocalVariablesLogProbability)) - { - trackLocalVariables(variableName); - } - } - - return ret; - } - - internal void LogVariable(List stmtList, string variableName) - { - stmtList.Add(GetLogInvokeStatement(variableName)); + return _testClass.PopScope(); } /// @@ -109,41 +95,40 @@ public TestMethod(TestClass enclosingClass, string methodName, bool isMainInvoca }; } - public virtual MethodDeclarationSyntax Generate() + public virtual MethodDeclStatement Generate() { PushScope(MethodScope); - MethodDeclarationSyntax methodDeclaration = GenerateMethodSignature(); - IList methodBody = new List(); + PopulateMethodSignature(); + + List methodBody = new List(); // TODO-TEMP initialize one variable of each type - foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) + foreach (var variableType in Tree.ValueType.GetTypes()) { - string variableName = Helpers.GetVariableName(variableType, _variablesCount++); + var variableName = Helpers.GetVariableName(variableType, _variablesCount++); - ExpressionSyntax rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); + var rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); - methodBody.Add(Annotate(LocalDeclarationStatement(Helpers.GetVariableDeclaration(variableType, variableName, rhs)), "var-init", 0)); + methodBody.Add(new VarDeclStatement(TC, variableType, variableName, rhs)); } // TODO-TEMP initialize one variable of each struct type - foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) + foreach (var structType in CurrentScope.AllStructTypes) { - string variableName = Helpers.GetVariableName(structType, _variablesCount++); + var variableName = Helpers.GetVariableName(structType, _variablesCount++); CurrentScope.AddLocal(structType, variableName); // Add all the fields to the scope var listOfStructFields = CurrentScope.GetStructFields(structType); - foreach(var structField in listOfStructFields) + foreach (var structField in listOfStructFields) { CurrentScope.AddLocal(structField.FieldType, $"{variableName}.{structField.FieldName}"); } - methodBody.Add(Annotate(LocalDeclarationStatement( - Helpers.GetVariableDeclaration(structType, variableName, - Helpers.GetObjectCreationExpression(structType.TypeName))), "struct-init", 0)); + methodBody.Add(new VarDeclStatement(TC, structType, variableName, new CreationExpression(TC, structType.TypeName, null))); if (!PRNG.Decide(TC.Config.StructAliasProbability)) { @@ -161,10 +146,7 @@ public virtual MethodDeclarationSyntax Generate() CurrentScope.AddLocal(structField.FieldType, $"{aliasVariableName}.{structField.FieldName}"); } - methodBody.Add(Annotate(LocalDeclarationStatement( - Helpers.GetVariableDeclaration(structType, aliasVariableName, - TestCase.GetExpressionSyntax(variableName))), "struct-alias-init", 0)); - + methodBody.Add(new VarDeclStatement(TC, structType, aliasVariableName, new VariableExpression(TC, variableName))); } // TODO-TEMP initialize out and ref method parameters @@ -189,40 +171,30 @@ public virtual MethodDeclarationSyntax Generate() //TODO-future: Select any assignOper //Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); - ExpressionSyntax lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.Data.ReturnType, 0); - ExpressionSyntax rhs = MethodCallHelper(nonLeafMethod.Data, 0); + var lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.Data.ReturnType, 0); + var rhs = MethodCallHelper(nonLeafMethod.Data, 0); - methodBody.Add(Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "MethodCall-Assign", 0)); - } - - // print all static variables - foreach (var variableName in _testClass.ClassScope.AllVariables) - { - methodBody.Add(GetLogInvokeStatement(variableName)); + methodBody.Add(new AssignStatement(TC, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs)); } } // print all variables - foreach (var variableName in CurrentScope.AllVariables) - { - methodBody.Add(GetLogInvokeStatement(variableName)); - } + methodBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); // return statement methodBody.Add(StatementHelper(StmtKind.ReturnStatement, 0)); - PopScope(variableName => { }); + PopScope(); RegisterMethod(MethodSignature); - // Wrap everything in unchecked so we do not see overflow compilation errors - return methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); + return new MethodDeclStatement(TC, MethodSignature, methodBody); } /// /// Generates method signature of this method. /// - protected virtual MethodDeclarationSyntax GenerateMethodSignature() + protected virtual void PopulateMethodSignature() { MethodSignature = new MethodSignature(Name); int numOfParameters = 0; @@ -234,7 +206,6 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() List parameters = new List(); MethodSignature.Parameters = parameters; - List parameterNodes = new List(); for (int paramIndex = 0; paramIndex < numOfParameters; paramIndex++) { @@ -268,7 +239,6 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() Debug.Assert(false, "invalid value for passingway!"); break; } - parameterNode = parameterNode.WithModifiers(TokenList(passingWayToken)); } parameters.Add(new MethodParam() @@ -277,17 +247,7 @@ protected virtual MethodDeclarationSyntax GenerateMethodSignature() ParamType = paramType, PassingWay = passingWay }); - parameterNodes.Add(parameterNode); - - if (paramIndex + 1 < numOfParameters) - { - parameterNodes.Add(Token(SyntaxKind.CommaToken)); - } } - - return MethodDeclaration(Helpers.GetTypeSyntax(MethodSignature.ReturnType), Name) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithParameterList(ParameterList(SeparatedList(parameterNodes))); } @@ -332,13 +292,10 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); Expression conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); - Scope ifBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); - Scope elseBranchScope = new Scope(TC, ScopeKind.ConditionalScope, CurrentScope); - int ifcount = PRNG.Next(1, TC.Config.MaxStatementCount); List ifBody = new List(); - PushScope(ifBranchScope); + PushScope(new Scope(TC, ScopeKind.ConditionalScope, CurrentScope)); for (int i = 0; i < ifcount; i++) { StmtKind cur; @@ -352,12 +309,14 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } ifBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => LogVariable(ifBody, variableName)); // pop 'if' body scope + ifBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); + + PopScope(); // pop 'if' body scope int elsecount = PRNG.Next(1, TC.Config.MaxStatementCount); List elseBody = new List(); - PushScope(elseBranchScope); + PushScope(new Scope(TC, ScopeKind.ConditionalScope, CurrentScope)); for (int i = 0; i < elsecount; i++) { StmtKind cur; @@ -371,7 +330,9 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } elseBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => LogVariable(elseBody, variableName)); // pop 'else' body scope + elseBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); + + PopScope(); // pop 'else' body scope return new IfElseStatement(TC, conditionExpr, ifBody, elseBody); } @@ -410,9 +371,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); - var forLoopScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); var loopVar = CurrentScope.GetRandomVariable(Tree.ValueType.ForPrimitive(Primitive.Int)); - var nestNum = depth; var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); var forLoopKind = Kind.ComplexLoop; @@ -422,10 +381,14 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) else if (PRNG.Next(2) == 0) forLoopKind = Kind.NormalLoop; - PushScope(forLoopScope); + PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); - var loopStep = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); + var loopStepCastExpr = ExprHelper(ExprKind.AssignExpression, Tree.ValueType.GetRandomType(), 0) as CastExpression; + + // No need to cast the assign expression inside for-loop. Additionally compiler would complain for it, so just + // unwrap the cast expression and use the real assignment expression. + var loopStep = loopStepCastExpr.Expression; //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack @@ -444,22 +407,19 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } forLoopBody.Add(StatementHelper(cur, depth + 1)); } + forLoopBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); - //TODO: This can just append to forLoopBody - PopScope(variableName => LogVariable(forLoopBody, variableName)); // pop 'for-loop' body scope + PopScope(); // pop 'for-loop' body scope - return new ForStatement(TC, loopVar, nestNum, numOfSecondaryVars, bounds, forLoopBody, loopStep, forLoopKind); + return new ForStatement(TC, loopVar, _loopVarCount++, numOfSecondaryVars, bounds, forLoopBody, loopStep, forLoopKind); } case StmtKind.DoWhileStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); - Scope doWhileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); - - var nestNum = depth; var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); - PushScope(doWhileScope); + PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); @@ -481,21 +441,19 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } whileLoopBody.Add(StatementHelper(cur, depth + 1)); } + whileLoopBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); - PopScope(variableName => LogVariable(whileLoopBody, variableName)); // pop 'do-while' body scope + PopScope(); // pop 'do-while' body scope - return new DoWhileStatement(TC, nestNum, numOfSecondaryVars, bounds, whileLoopBody); + return new DoWhileStatement(TC, _loopVarCount++, numOfSecondaryVars, bounds, whileLoopBody); } case StmtKind.WhileStatement: { //Debug.Assert(depth <= TC.Config.MaxStmtDepth); - Scope whileScope = new Scope(TC, ScopeKind.LoopScope, CurrentScope); - - var nestNum = depth; var numOfSecondaryVars = PRNG.Next(/*GetOptions().MaxNumberOfSecondaryInductionVariable*/ 1 + 1); - PushScope(whileScope); + PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); @@ -517,10 +475,11 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } whileLoopBody.Add(StatementHelper(cur, depth + 1)); } + whileLoopBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); - PopScope(variableName => LogVariable(whileLoopBody, variableName)); // pop 'while' body scope + PopScope(); // pop 'while' body scope - return new WhileStatement(TC, nestNum, numOfSecondaryVars, bounds, whileLoopBody); + return new WhileStatement(TC, _loopVarCount++, numOfSecondaryVars, bounds, whileLoopBody); } case StmtKind.ReturnStatement: { @@ -543,8 +502,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) bool hasFinally = catchCounts == 0 || PRNG.Decide(TC.Config.FinallyClauseProbability); List tryBody = new List(); - Scope tryScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(tryScope); + PushScope(new Scope(TC, ScopeKind.BracesScope, CurrentScope)); int tryStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); for (int i = 0; i < tryStmtCount; i++) @@ -560,7 +518,9 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } tryBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => LogVariable(tryBody, variableName)); // pop 'try' body scope + tryBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); + + PopScope(); // pop 'try' body scope List>> catchClauses = new (); @@ -582,8 +542,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) int catchStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); List catchBody = new List(); - Scope catchScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(catchScope); + PushScope(new Scope(TC, ScopeKind.BracesScope, CurrentScope)); for (int i = 0; i < catchStmtCount; i++) { @@ -598,15 +557,16 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } catchBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => LogVariable(catchBody, variableName)); // pop 'catch' body scope + catchBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); + + PopScope(); // pop 'catch' body scope catchClauses.Add(Tuple.Create(exceptionToCatch, catchBody)); } List finallyBody = new List(); if (hasFinally) { - Scope finallyScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(finallyScope); + PushScope(new Scope(TC, ScopeKind.BracesScope, CurrentScope)); int finallyStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); for (int i = 0; i < finallyStmtCount; i++) @@ -622,7 +582,9 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } finallyBody.Add(StatementHelper(cur, depth + 1)); } - PopScope(variableName => LogVariable(finallyBody, variableName)); // pop 'finally' body scope + finallyBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); + + PopScope(); // pop 'finally' body scope } return new TryCatchFinallyStatement(TC, tryBody, catchClauses, finallyBody); @@ -644,8 +606,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) // Generate each cases for (int i = 0; i < caseCount; i++) { - Scope caseScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(caseScope); + PushScope(new Scope(TC, ScopeKind.BracesScope, CurrentScope)); // Generate statements within each cases int caseStmtCount = PRNG.Next(1, TC.Config.MaxStatementCount); @@ -663,8 +624,9 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } caseBody.Add(StatementHelper(cur, depth + 1)); } + caseBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); - PopScope(variableName => LogVariable(caseBody, variableName)); // pop 'case' body scope + PopScope(); // pop 'case' body scope ConstantValue caseConstantValue; do @@ -676,8 +638,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } // Generate default - var defaultScope = new Scope(TC, ScopeKind.BracesScope, CurrentScope); - PushScope(defaultScope); + PushScope(new Scope(TC, ScopeKind.BracesScope, CurrentScope)); // Generate statements within default int defaultStmtCount = PRNG.Next(1, 3); @@ -695,8 +656,9 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } defaultBody.Add(StatementHelper(cur, depth + 1)); } + defaultBody.Add(GetLogInvocationStatement(CurrentScope.LocalVariableNames, TC.Config.LocalVariablesLogProbability)); - PopScope(variableName => LogVariable(defaultBody, variableName)); // pop 'default' body scope + PopScope(); // pop 'default' body scope return new SwitchStatement(TC, switchExpr, listOfCases, defaultBody); } @@ -781,7 +743,7 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep Expression lhs = ExprHelper(lhsExprKind, lhsExprType, depth + 1); Expression rhs = ExprHelper(rhsExprKind, rhsExprType, depth + 1); - return new CastExpression(TC, new BinaryExpression(TC, lhs, op, rhs), exprType); + return new CastExpression(TC, new BinaryExpression(TC, lhsExprType, lhs, op, rhs), exprType); } case ExprKind.AssignExpression: { @@ -810,7 +772,7 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); Expression rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); - return new CastExpression(TC, new AssignExpression(TC, lhs, assignOper, rhs), exprType); + return new CastExpression(TC, new AssignExpression(TC, lhsExprType, lhs, assignOper, rhs), exprType); } case ExprKind.MethodCallExpression: { @@ -835,24 +797,24 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep /// Generates assignment for variable name /// /// - public StatementSyntax VariableAssignmentHelper(Tree.ValueType exprType, string variableName) + public Statement VariableAssignmentHelper(Tree.ValueType exprType, string variableName) { - ExpressionSyntax lhs = Annotate(TestCase.GetExpressionSyntax(variableName), "specific-Var"); - ExpressionSyntax rhs; + Expression lhs = new VariableExpression(TC, variableName); + Expression rhs; int noOfAttempts = TC.Config.NumOfAttemptsForExpression; do { rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(exprType.PrimitiveType), exprType, 0); // Make sure that we do not end up with same lhs=lhs. - if (lhs.ToFullString() != rhs.ToFullString()) + if (lhs.ToString() != rhs.ToString()) { break; } } while (noOfAttempts++ < 5); - Debug.Assert(lhs.ToFullString() != rhs.ToFullString()); + Debug.Assert(lhs.ToString() != rhs.ToString()); - return Annotate(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, lhs, rhs)), "specific-Assign", 0); + return new AssignStatement(TC, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs); } /// @@ -1006,25 +968,22 @@ private StatementSyntax Annotate(StatementSyntax statement, string comment, int /// - /// Generate log invoke statement + /// Bulk generate log invocation statements for all . /// - /// + /// /// - public static StatementSyntax GetLogInvokeStatement(string variableName) + public static ArbitraryCodeStatement GetLogInvocationStatement(List variableNames, double logProbability) { - return ExpressionStatement( - PreGenerated.LogInvocationExpression - .WithArgumentList( - ArgumentList( - SeparatedList( - new SyntaxNodeOrToken[] - { - // For variable names, just take 10 characters for longer variable names - Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(variableName.Substring(0, Math.Min(variableName.Length, 10))))), - Token(SyntaxKind.CommaToken), - Argument(TestCase.GetExpressionSyntax(variableName)) - } - )))); + var strBuilder = new StringBuilder(); + // For variable names, just take 10 characters for longer variable names + variableNames.ForEach(variableToLog => + { + if (PRNG.Decide(logProbability)) + { + strBuilder.AppendLine($"Log(\"{variableToLog.Substring(0, Math.Min(variableToLog.Length, 10))}\", {variableToLog});"); + } + }); + return new ArbitraryCodeStatement(null, strBuilder.ToString()); } } @@ -1034,13 +993,15 @@ public class MethodSignature public Tree.ValueType ReturnType; public List Parameters; public bool IsLeaf; + public bool IsNoInline; - public MethodSignature(string methodName, bool isLeaf = false) + public MethodSignature(string methodName, bool isLeaf = false, bool isNoInline = false) { MethodName = methodName; ReturnType = Tree.ValueType.ForVoid(); Parameters = new List(); IsLeaf = isLeaf; + IsNoInline = isNoInline; } public override bool Equals(object obj) @@ -1104,42 +1065,32 @@ public TestLeafMethod(TestClass enclosingClass, string methodName, Tree.ValueTyp _returnType = returnType; } - protected override MethodDeclarationSyntax GenerateMethodSignature() + protected override void PopulateMethodSignature() { - MethodSignature = new MethodSignature(Name, isLeaf: true) + MethodSignature = new MethodSignature(Name) { Parameters = new List(), - ReturnType = _returnType + ReturnType = _returnType, + IsLeaf = true, + IsNoInline = PRNG.Decide(0.5) }; - - var methodDecl = MethodDeclaration(Helpers.GetTypeSyntax(_returnType), Name) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); - - //TODO-config: 50% of time, add attribute of NoInline - if (PRNG.Decide(0.5)) - { - methodDecl = methodDecl.WithAttributeLists(Helpers.NoInlineAttr); - } - - return methodDecl; } - public override MethodDeclarationSyntax Generate() + public override MethodDeclStatement Generate() { GetASTUtils().EnterLeafMethod(); // return statement - MethodDeclarationSyntax methodDeclaration = GenerateMethodSignature(); - IList methodBody = new List(); + PopulateMethodSignature(); + List methodBody = new List(); methodBody.Add(StatementHelper(StmtKind.ReturnStatement, 0)); RegisterMethod(MethodSignature); - // Wrap everything in unchecked so we do not see overflow compilation errors - var leafMethod = methodDeclaration.WithBody(Block(CheckedStatement(SyntaxKind.UncheckedStatement, Block(methodBody)))); GetASTUtils().LeaveLeafMethod(); - return leafMethod; + + return new MethodDeclStatement(TC, MethodSignature, methodBody); } } } diff --git a/Tree/Node.cs b/Tree/Node.cs index c19253d..09e8055 100644 --- a/Tree/Node.cs +++ b/Tree/Node.cs @@ -13,7 +13,7 @@ namespace Antigen.Tree public abstract class Node { protected TestCase _testCase; - protected string _contents; + //protected string _contents; //public virtual void Render(RenderContext renderContext) //{ @@ -21,13 +21,13 @@ public abstract class Node //} //TODO: Have this call an abstract method - public override string ToString() - { - return Annotate(); - } + //public override string ToString() + //{ + // return string.Empty; + //} protected abstract string Annotate(); - protected virtual void PopulateContent() { } + //protected virtual void PopulateContent() { } public Node(TestCase tc) { diff --git a/Tree/Scope.cs b/Tree/Scope.cs index b48ac0f..e644cbd 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Antigen.Statements; namespace Antigen.Tree { @@ -36,7 +37,7 @@ public class Scope // List of local variables in current scope. private Dictionary> LocalVariables = new Dictionary>(); - public List AllVariables => LocalVariables.SelectMany(dict => dict.Value).ToList(); + public List LocalVariableNames => LocalVariables.SelectMany(dict => dict.Value).ToList(); // A mapping of all the primitive fields present in given struct // Every time a variable "xyz" of one of the struct is defined, all the fields corresponding to that struct @@ -67,8 +68,23 @@ public Scope(TestCase tc, ScopeKind t, Scope parentScope) #region Get variables/types from the scope public string GetRandomVariable(ValueType variableType) { - List allUsableVariables = GetUsableVariables(variableType); - return allUsableVariables[PRNG.Next(allUsableVariables.Count)]; + var defaultVariable = string.Empty; + var curr = this; + + while (curr != null) + { + if (curr.ListOfVariables.TryGetValue(variableType, out var variables)) + { + defaultVariable = variables[PRNG.Next(variables.Count)]; + + if (PRNG.Decide(0.3)) + { + return defaultVariable; + } + } + curr = curr.parent; + } + return defaultVariable; } public ValueType GetRandomStructType() @@ -88,17 +104,17 @@ public int GetVariablesCount() #region Add variables/types to scope public void AddLocal(ValueType variableType, string variableName) { -#if DEBUG - foreach (var valueType in LocalVariables.Keys) - { - Debug.Assert(!LocalVariables[valueType].Contains(variableName)); - } - - foreach (var valueType in ListOfVariables.Keys) - { - Debug.Assert(!ListOfVariables[valueType].Contains(variableName)); - } -#endif +//#if DEBUG +// foreach (var valueType in LocalVariables.Keys) +// { +// Debug.Assert(!LocalVariables[valueType].Contains(variableName)); +// } + +// foreach (var valueType in ListOfVariables.Keys) +// { +// Debug.Assert(!ListOfVariables[valueType].Contains(variableName)); +// } +//#endif // Add to local variables if (!LocalVariables.ContainsKey(variableType)) { @@ -122,8 +138,10 @@ public void AddLocal(ValueType variableType, string variableName) /// /// It also resolves all the fields present in /// and store the fully qualifier name in . + /// + /// Returns the new structType created. /// - public void AddStructType(string typeName, List structFields) + public ValueType AddStructType(string typeName, List structFields) { ValueType newStructType = ValueType.CreateStructType(typeName); List fieldsInCurrStruct = new List(); @@ -160,6 +178,7 @@ public void AddStructType(string typeName, List structFields) StructToFieldsMapping[newStructType] = fieldsInCurrStruct; ListOfStructTypes.Add(newStructType); + return newStructType; } #endregion @@ -172,7 +191,6 @@ public void AddStructType(string typeName, List structFields) private List GetUsableVariables(ValueType variableType) { List variables = new List(); - Scope curr = this; while (curr != null) diff --git a/Tree/Types.cs b/Tree/Types.cs index 98df511..938f2e2 100644 --- a/Tree/Types.cs +++ b/Tree/Types.cs @@ -68,28 +68,30 @@ public string TypeName } } + private string _variableNameHint; private string _structTypeName; public Primitive PrimitiveType; //private TypeFlags Flags; public SpecialType DataType; public SyntaxKind TypeKind; + private string _displayText; private static readonly List types = new List() { - new ValueType(Primitive.Boolean, SpecialType.System_Boolean, SyntaxKind.BoolKeyword), - new ValueType(Primitive.Byte, SpecialType.System_Byte, SyntaxKind.ByteKeyword), - new ValueType(Primitive.Char, SpecialType.System_Char, SyntaxKind.CharKeyword), - new ValueType(Primitive.Decimal, SpecialType.System_Decimal, SyntaxKind.DecimalKeyword), - new ValueType(Primitive.Double, SpecialType.System_Double, SyntaxKind.DoubleKeyword), - new ValueType(Primitive.Short, SpecialType.System_Int16, SyntaxKind.ShortKeyword), - new ValueType(Primitive.Int, SpecialType.System_Int32, SyntaxKind.IntKeyword), - new ValueType(Primitive.Long, SpecialType.System_Int64, SyntaxKind.LongKeyword), - new ValueType(Primitive.SByte, SpecialType.System_SByte, SyntaxKind.SByteKeyword), - new ValueType(Primitive.Float, SpecialType.System_Single, SyntaxKind.FloatKeyword), - new ValueType(Primitive.String, SpecialType.System_String, SyntaxKind.StringKeyword), - new ValueType(Primitive.UShort, SpecialType.System_UInt16, SyntaxKind.UShortKeyword), - new ValueType(Primitive.UInt, SpecialType.System_UInt32, SyntaxKind.UIntKeyword), - new ValueType(Primitive.ULong, SpecialType.System_UInt64, SyntaxKind.ULongKeyword), + new ValueType(Primitive.Boolean, "bool", SpecialType.System_Boolean, SyntaxKind.BoolKeyword), + new ValueType(Primitive.Byte, "byte", SpecialType.System_Byte, SyntaxKind.ByteKeyword), + new ValueType(Primitive.Char, "char", SpecialType.System_Char, SyntaxKind.CharKeyword), + new ValueType(Primitive.Decimal, "decimal", SpecialType.System_Decimal, SyntaxKind.DecimalKeyword), + new ValueType(Primitive.Double, "double", SpecialType.System_Double, SyntaxKind.DoubleKeyword), + new ValueType(Primitive.Short, "short", SpecialType.System_Int16, SyntaxKind.ShortKeyword), + new ValueType(Primitive.Int, "int", SpecialType.System_Int32, SyntaxKind.IntKeyword), + new ValueType(Primitive.Long, "long", SpecialType.System_Int64, SyntaxKind.LongKeyword), + new ValueType(Primitive.SByte, "sbyte", SpecialType.System_SByte, SyntaxKind.SByteKeyword), + new ValueType(Primitive.Float, "float", SpecialType.System_Single, SyntaxKind.FloatKeyword), + new ValueType(Primitive.String, "string", SpecialType.System_String, SyntaxKind.StringKeyword), + new ValueType(Primitive.UShort, "ushort", SpecialType.System_UInt16, SyntaxKind.UShortKeyword), + new ValueType(Primitive.UInt, "uint", SpecialType.System_UInt32, SyntaxKind.UIntKeyword), + new ValueType(Primitive.ULong, "ulong", SpecialType.System_UInt64, SyntaxKind.ULongKeyword), }; /// @@ -168,17 +170,20 @@ public bool CanConvert(ValueType toType) public static ValueType CreateStructType(string typeName) { - var structType = new ValueType(Primitive.Struct, SpecialType.None, SyntaxKind.None); + var structType = new ValueType(Primitive.Struct, typeName,/* $"struct {typeName}",*/ SpecialType.None, SyntaxKind.None); structType._structTypeName = typeName; + structType._variableNameHint = typeName.ToLower().Replace(".", "_").ToLower(); return structType; } - private ValueType(Primitive valueType, SpecialType dataType, SyntaxKind typeKind) + private ValueType(Primitive valueType, string displayText, SpecialType dataType, SyntaxKind typeKind) { PrimitiveType = valueType; DataType = dataType; TypeKind = typeKind; _structTypeName = null; + _displayText = displayText; + _variableNameHint = displayText; } public static List GetTypes() @@ -186,6 +191,11 @@ public static List GetTypes() return types; } + public static ValueType GetRandomType() + { + return types[PRNG.Next(types.Count)]; + } + public override bool Equals(object obj) { ValueType otherType = (ValueType)obj; @@ -210,7 +220,7 @@ public static ValueType ForPrimitive(Primitive primitiveType) return types.First(t => t.PrimitiveType == primitiveType); } - private static ValueType voidType = new ValueType(Primitive.Void, SpecialType.System_Void, SyntaxKind.VoidKeyword); + private static ValueType voidType = new ValueType(Primitive.Void, "void", SpecialType.System_Void, SyntaxKind.VoidKeyword); public static ValueType ForVoid() { return voidType; @@ -218,14 +228,15 @@ public static ValueType ForVoid() public string VariableNameHint() { - if (PrimitiveType != Primitive.Struct) - { - return Enum.GetName(typeof(SpecialType), DataType).Replace("System_", "").ToLower(); - } - else - { - return TypeName.ToLower().Replace(".", "_").ToLower(); - } + //if (PrimitiveType != Primitive.Struct) + //{ + // return _displayText; // Enum.GetName(typeof(SpecialType), DataType).Replace("System_", "").ToLower(); + //} + //else + //{ + // return TypeName.ToLower().Replace(".", "_").ToLower(); + //} + return _variableNameHint; } public static IDictionary AllExceptions => @@ -236,14 +247,7 @@ public string VariableNameHint() public override string ToString() { - if (PrimitiveType != Primitive.Struct) - { - return Enum.GetName(typeof(Primitive), PrimitiveType); - } - else - { - return $"struct {_structTypeName}"; - } + return _displayText; } } } diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 99482ef..5530f4e 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -422,7 +422,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< StringBuilder fileContents = new StringBuilder(); fileContents.AppendLine(programContents); fileContents.AppendLine("/*"); - fileContents.AppendLine($"Got output diff:"); + fileContents.AppendLine("Got output diff:"); fileContents.AppendLine("--------- Baseline --------- "); fileContents.AppendLine(); @@ -432,7 +432,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< { foreach (var envVars in baselineEnvVars) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); } } fileContents.AppendLine(); @@ -444,7 +444,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine(); foreach (var envVars in testEnvVars) { - fileContents.AppendLine($"{envVars.Key}={envVars.Value}"); + fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); } fileContents.AppendLine(); fileContents.AppendLine(currRunTestOutput); From f0a087f8ce953246288b227ea764c8a2152913b9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Sep 2021 13:03:09 -0700 Subject: [PATCH 072/149] Some fixes --- Config/antigen.json | 3 +- Expressions/AssignExpression.cs | 1 - Helpers/Expressions.cs | 67 ------------- Helpers/Literals.cs | 109 --------------------- Helpers/PreGenerated.cs | 31 ++---- Helpers/TestRunner.cs | 14 ++- Helpers/VariableDeclarationHelper.cs | 139 --------------------------- Program.cs | 8 +- TestCase.cs | 60 +++--------- TestMethod.cs | 21 ---- 10 files changed, 35 insertions(+), 418 deletions(-) delete mode 100644 Helpers/Expressions.cs diff --git a/Config/antigen.json b/Config/antigen.json index ea0d8b0..3ef88df 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,5 +1,5 @@ { - "Seed": 1, + "Seed": -1, "OutputDirectory": ".", "NumTestCases": 1000, "HoursToRun": 10, @@ -49,7 +49,6 @@ "Name": "JitAlignLoopAdaptive", "Weight": 0.01, "Values": [ - "0", "1" ] }, diff --git a/Expressions/AssignExpression.cs b/Expressions/AssignExpression.cs index 8d21655..216b737 100644 --- a/Expressions/AssignExpression.cs +++ b/Expressions/AssignExpression.cs @@ -8,7 +8,6 @@ using System.Text; using System.Threading.Tasks; using Antigen.Tree; -using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Expressions { diff --git a/Helpers/Expressions.cs b/Helpers/Expressions.cs deleted file mode 100644 index e92f974..0000000 --- a/Helpers/Expressions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Antigen.Tree; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -using ValueType = Antigen.Tree.ValueType; - -namespace Antigen -{ - public static partial class Helpers - { - public static BinaryExpressionSyntax GetBinaryExpression(ExpressionSyntax lhs, Operator op, ExpressionSyntax rhs) - { - return BinaryExpression(op.Oper, lhs, rhs); - } - - public static ParenthesizedExpressionSyntax GetWrappedAndCastedExpression(ValueType fromType, ValueType toType, ExpressionSyntax expr) - { - //Debug.Assert(fromType.CanConvert(toType) || toType.PrimitiveType == Primitive.Boolean); - ParenthesizedExpressionSyntax parenExpr = ParenthesizedExpression(expr); - - //if (fromType.CanConvertExplicit(toType)) - //{ - parenExpr = ParenthesizedExpression(CastExpression(Helpers.GetToken(toType.TypeKind), parenExpr)); - //} - //else - //{ - // Debug.Assert(fromType.CanConvertImplicit(toType) || toType.PrimitiveType == Primitive.Boolean); - //} - - return parenExpr; - } - - public static SyntaxList NoInlineAttr => - SingletonList( - AttributeList( - SingletonSeparatedList( - Attribute( - IdentifierName("MethodImpl")) - .WithArgumentList( - AttributeArgumentList( - SingletonSeparatedList( - AttributeArgument( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName("MethodImplOptions"), - IdentifierName("NoInlining"))))))))); - - /// - /// Converts a to . - /// - /// - /// - /// - public static SyntaxList ToSyntaxList(this IList list) where T : SyntaxNode - { - return new SyntaxList(list); - } - } -} diff --git a/Helpers/Literals.cs b/Helpers/Literals.cs index b266172..5ed7646 100644 --- a/Helpers/Literals.cs +++ b/Helpers/Literals.cs @@ -93,114 +93,5 @@ public static decimal GetRandomDecimal() { return (decimal)PRNG.Next(10) + (1 / PRNG.Next(1, 5)); } - - public static LiteralExpressionSyntax GetLiteralExpression(Tree.ValueType literalType, IList> numerals) - { - SyntaxToken literalToken; - SyntaxKind kind; - - if ((literalType.PrimitiveType & Primitive.Numeric) != 0) - { - // numeric - kind = SyntaxKind.NumericLiteralExpression; - int literalValue = PRNG.WeightedChoice(numerals); - - // If unsigned, and number selected is negative, then flip it - if ((literalType.PrimitiveType & Primitive.UnsignedInteger) != 0) - { - if (literalValue < 0) - { - if (literalValue == int.MinValue) - { - literalValue = int.MaxValue; - } - else - { - literalValue *= -1; - } - } - } - - switch (literalType.PrimitiveType) - { - case Tree.Primitive.Byte: - literalToken = Literal((byte)(literalValue % byte.MaxValue)); - break; - case Tree.Primitive.SByte: - literalToken = Literal((sbyte)(literalValue % sbyte.MaxValue)); - break; - case Tree.Primitive.UShort: - literalToken = Literal((ushort)(literalValue % ushort.MaxValue)); - break; - case Tree.Primitive.Short: - literalToken = Literal((short)(literalValue % short.MaxValue)); - break; - case Tree.Primitive.Int: - literalToken = Literal(literalValue); - break; - case Tree.Primitive.UInt: - literalToken = Literal(literalValue); - break; - case Tree.Primitive.Long: - literalToken = Literal(literalValue); - break; - case Tree.Primitive.ULong: - literalToken = Literal(literalValue); - break; - case Tree.Primitive.Float: - literalToken = Literal((float)literalValue + (float)PRNG.Next(5) / PRNG.Next(10, 100)); - break; - case Tree.Primitive.Decimal: - literalToken = Literal((decimal)literalValue + (decimal)PRNG.Next(5) / PRNG.Next(10, 100)); - break; - case Tree.Primitive.Double: - literalToken = Literal((double)literalValue + (double)PRNG.Next(5) / PRNG.Next(10, 100)); - break; - default: - Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); - - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(1); - break; - } - } - else - { - // non-numeric - switch (literalType.PrimitiveType) - { - case Tree.Primitive.Boolean: - if (GetRandomBoolean()) - { - kind = SyntaxKind.TrueLiteralExpression; - literalToken = Token(SyntaxKind.TrueKeyword); - } - else - { - kind = SyntaxKind.FalseLiteralExpression; - literalToken = Token(SyntaxKind.FalseKeyword); - } - break; - - case Tree.Primitive.Char: - kind = SyntaxKind.CharacterLiteralExpression; - literalToken = Literal(GetRandomChar()); - break; - - case Tree.Primitive.String: - kind = SyntaxKind.StringLiteralExpression; - literalToken = Literal(GetRandomString()); - break; - default: - Debug.Assert(false, String.Format("Hit unknown value type {0}", Enum.GetName(typeof(Tree.Primitive), literalType.PrimitiveType))); - - kind = SyntaxKind.NumericLiteralExpression; - literalToken = Literal(1); - break; - } - } - - return LiteralExpression(kind, literalToken); - } } } diff --git a/Helpers/PreGenerated.cs b/Helpers/PreGenerated.cs index 507ae51..bf832a4 100644 --- a/Helpers/PreGenerated.cs +++ b/Helpers/PreGenerated.cs @@ -7,15 +7,16 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +//using Microsoft.CodeAnalysis.CSharp.Syntax; +//using Microsoft.CodeAnalysis.CSharp; +//using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using Antigen.Statements; namespace Antigen { public static class PreGenerated { + public static readonly string MainClassName = "TestClass"; private static ArbitraryCodeStatement s_usingStmts = null; /// /// Returns code related to using directives. @@ -63,7 +64,10 @@ public static Statement StaticMethods StringBuilder staticMethodBuilder = new StringBuilder(); // Main method - staticMethodBuilder.AppendLine("public static void Main(string[] args) { }"); + staticMethodBuilder.AppendLine("public static void Main(string[] args) { "); + staticMethodBuilder.AppendLine($"new {MainClassName}().Method0();"); + staticMethodBuilder.AppendLine("PrintLog();"); + staticMethodBuilder.AppendLine("}"); // Log method staticMethodBuilder.AppendLine("[MethodImpl(MethodImplOptions.NoInlining)]"); @@ -82,24 +86,5 @@ public static Statement StaticMethods return s_staticMethods; } } - - private static MemberDeclarationSyntax loggerVarDecl = null; - - /// - /// Returns declaration of logger variable - /// - public static MemberDeclarationSyntax LoggerVariableDecl - { - get - { - if (loggerVarDecl == null) - { - loggerVarDecl = ParseMemberDeclaration("private static List toPrint = new List();"); - } - return loggerVarDecl; - } - } - - public static InvocationExpressionSyntax LogInvocationExpression = SyntaxFactory.InvocationExpression(IdentifierName("Log")); } } diff --git a/Helpers/TestRunner.cs b/Helpers/TestRunner.cs index a7d0885..bcdbedf 100644 --- a/Helpers/TestRunner.cs +++ b/Helpers/TestRunner.cs @@ -79,8 +79,8 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) #endif } - //ms.Seek(0, SeekOrigin.Begin); - //File.WriteAllBytes(assemblyFullPath, ms.ToArray()); + ms.Seek(0, SeekOrigin.Begin); + File.WriteAllBytes(assemblyFullPath, ms.ToArray()); //Console.WriteLine($"{ms.Length} bytes"); return new CompileResult(assemblyName, assemblyFullPath); @@ -167,12 +167,18 @@ internal string Execute(CompileResult compileResult, Dictionary StringBuilder output = new StringBuilder(); proc.OutputDataReceived += new DataReceivedEventHandler((s, e) => { - output.AppendLine(e.Data); + if (!string.IsNullOrEmpty(e.Data)) + { + output.AppendLine(e.Data); + } }); proc.ErrorDataReceived += new DataReceivedEventHandler((s, e) => { - output.AppendLine(e.Data); + if (!string.IsNullOrEmpty(e.Data)) + { + output.AppendLine(e.Data); + } }); proc.BeginOutputReadLine(); diff --git a/Helpers/VariableDeclarationHelper.cs b/Helpers/VariableDeclarationHelper.cs index f1314c5..473a5c5 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Helpers/VariableDeclarationHelper.cs @@ -1,155 +1,16 @@ using Antigen.Tree; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen { public static partial class Helpers { - public static VariableDeclarationSyntax GetVariableDeclaration(Tree.ValueType variableType, string variableName, ExpressionSyntax value = null) - { - VariableDeclarationSyntax varDecl; - if (variableType.PrimitiveType == Primitive.Struct) - { - varDecl = GetVariableDeclaration(variableType.TypeName, variableName); - } - else - { - varDecl = VariableDeclaration(PredefinedType(Token(variableType.TypeKind))); - } - - var declarator = VariableDeclarator(Identifier(variableName)); - if (value != null) - { - declarator = declarator.WithInitializer(EqualsValueClause(value)); - } - return varDecl.WithVariables(SingletonSeparatedList(declarator)); - } - - private static VariableDeclarationSyntax GetVariableDeclaration(string variableType, string variableName) - { - TypeSyntax variableTypeSyntax; - if (variableType.Contains('.')) - { - string[] seperatedTypes = variableType.Split('.', StringSplitOptions.RemoveEmptyEntries); - NameSyntax nameSyntax = QualifiedName( - IdentifierName(seperatedTypes[0]), - IdentifierName(seperatedTypes[1])); - for (int subType = 2; subType < seperatedTypes.Length; subType++) - { - nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); - } - variableTypeSyntax = nameSyntax; - } - else - { - variableTypeSyntax = IdentifierName(variableType); - } - - var varDecl = VariableDeclarator(Identifier(variableName)); - return VariableDeclaration(variableTypeSyntax) - .WithVariables(SingletonSeparatedList(varDecl)); - } - public static string GetVariableName(Tree.ValueType variableType, int id) { return variableType.VariableNameHint() + "_" + id; } - - public static PredefinedTypeSyntax GetToken(SyntaxKind syntaxKind) - { - return PredefinedType(Token(syntaxKind)); - } - - public static ExpressionSyntax GetVariableAccessExpression(string variableName) - { - if (variableName.Contains('.')) - { - string[] seperatedFields = variableName.Split('.', StringSplitOptions.RemoveEmptyEntries); - var memberAccessExpr = MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(seperatedFields[0]), - IdentifierName(seperatedFields[1])); - for (int subType = 2; subType < seperatedFields.Length; subType++) - { - memberAccessExpr = MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - memberAccessExpr, - IdentifierName(seperatedFields[subType])); - } - - return memberAccessExpr; - } - else - { - return IdentifierName(variableName); - } - } - - public static ObjectCreationExpressionSyntax GetObjectCreationExpression(string objectType) - { - TypeSyntax objectTypeSyntax; - - if (objectType.Contains('.')) - { - string[] seperatedTypes = objectType.Split('.', StringSplitOptions.RemoveEmptyEntries); - NameSyntax nameSyntax = QualifiedName( - IdentifierName(seperatedTypes[0]), - IdentifierName(seperatedTypes[1])); - for (int subType = 2; subType < seperatedTypes.Length; subType++) - { - nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); - } - objectTypeSyntax = nameSyntax; - } - else - { - objectTypeSyntax = IdentifierName(objectType); - } - return ObjectCreationExpression(objectTypeSyntax).WithArgumentList( - ArgumentList()); - } - - //TODO: Reuse in GetVariableDeclaration - public static ParameterSyntax GetParameterSyntax(Tree.ValueType variableType, string variableName) - { - ParameterSyntax parameterSyntax = Parameter(Identifier(variableName)); - return parameterSyntax.WithType(GetTypeSyntax(variableType)); - } - - //TODO: Reuse in GetVariableDeclaration - public static TypeSyntax GetTypeSyntax(Tree.ValueType variableType) - { - if (variableType.PrimitiveType == Primitive.Struct) - { - if (!variableType.TypeName.Contains(".")) - { - return IdentifierName(variableType.TypeName); - } - - // contains nested struct - string[] seperatedTypes = variableType.TypeName.Split('.', StringSplitOptions.RemoveEmptyEntries); - NameSyntax nameSyntax = QualifiedName( - IdentifierName(seperatedTypes[0]), - IdentifierName(seperatedTypes[1])); - for (int subType = 2; subType < seperatedTypes.Length; subType++) - { - nameSyntax = QualifiedName(nameSyntax, IdentifierName(seperatedTypes[subType])); - } - return nameSyntax; - } - else - { - return GetToken(variableType.TypeKind); - } - } } } diff --git a/Program.cs b/Program.cs index e830a14..65b3694 100644 --- a/Program.cs +++ b/Program.cs @@ -19,7 +19,8 @@ class Program { TestResult.RoslynException, 0 }, { TestResult.CompileError, 0 }, { TestResult.Assertion, 0 }, - { TestResult.KnownErrors, 0 }, + { TestResult.DivideByZero, 0 }, + { TestResult.Overflow, 0 }, { TestResult.OutputMismatch, 0 }, { TestResult.Pass, 0 }, { TestResult.OOM, 0 }, @@ -57,7 +58,7 @@ static void Main(string[] args) // return; //} - Parallel.For(0, 4, (p) => RunTest()); + Parallel.For(0, 2, (p) => RunTest()); } catch (OutOfMemoryException oom) @@ -115,7 +116,8 @@ static void RunTest() { TestResult.RoslynException, 0 }, { TestResult.CompileError, 0 }, { TestResult.Assertion, 0 }, - { TestResult.KnownErrors, 0 }, + { TestResult.DivideByZero, 0 }, + { TestResult.Overflow, 0 }, { TestResult.OutputMismatch, 0 }, { TestResult.Pass, 0 }, { TestResult.OOM, 0 }, diff --git a/TestCase.cs b/TestCase.cs index 01e01cf..6e12b77 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -26,7 +26,8 @@ public enum TestResult { RoslynException, CompileError, - KnownErrors, + Overflow, + DivideByZero, OutputMismatch, Assertion, Pass, @@ -44,9 +45,6 @@ public enum CompilationType #endregion - #region PreComputed roslyn syntax tress - #endregion - private readonly List _knownDiffs = new List() { "System.OverflowException: Value was either too large or too small for a Decimal.", @@ -75,23 +73,6 @@ public enum CompilationType private static readonly ConcurrentDictionary _variableExpressions = new(); - public static ExpressionSyntax GetExpressionSyntax(string variableName) - { - // Cache max 1000 expressions after which recycle them. - if (_variableExpressions.Count > 1000) - { - _variableExpressions.Clear(); - } - - if (!_variableExpressions.TryGetValue(variableName, out var exprSyntax)) - { - exprSyntax = Helpers.GetVariableAccessExpression(variableName); - _variableExpressions[variableName] = exprSyntax; - } - - return exprSyntax; - } - //private List classesList; //private List methodsList; //private List propertiesList; @@ -116,18 +97,10 @@ public TestCase(int testId, RunOptions runOptions) public void Generate() { - var klass = new TestClass(this, Name).Generate(); + var klass = new TestClass(this, PreGenerated.MainClassName).Generate(); var finalCode = PreGenerated.UsingDirective + klass.ToString(); testCaseRoot = CSharpSyntaxTree.ParseText(finalCode).GetRoot(); - - //string formattedContents = testCaseRoot.NormalizeWhitespace().SyntaxTree.GetText().ToString(); - - File.WriteAllText(@"e:\perfinvestigation\minibench\Antigen.cs", finalCode); - //File.WriteAllText(@"e:\perfinvestigation\minibench\Antigen.cs", testCaseRoot.ToFullString()); - //var _1 = CSharpSyntaxTree.ParseText(finalCode).GetRoot(); - //var _2 = CSharpSyntaxTree.ParseText(CSharpSyntaxTree.ParseText(finalCode).GetRoot().ToFullString()); - Console.WriteLine(); } public TestResult Verify() @@ -155,17 +128,16 @@ public TestResult Verify() #if UNREACHABLE else { - string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); + string workingFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-working.g.cs"); File.WriteAllText(workingFile, testCaseRoot.ToFullString()); } #endif - var baselineVariables = EnvVarOptions.BaseLineVars(); var testVariables = EnvVarOptions.TestVars(); // Execute test first and see if we have any errors/asserts - string test = s_testRunner.Execute(compileResult, testVariables, 30); - string testAssertion = RslnUtilities.ParseAssertionError(test); + var test = s_testRunner.Execute(compileResult, testVariables, 30); + var testAssertion = RslnUtilities.ParseAssertionError(test); // If OOM, skip if (test.Contains("Out of memory")) @@ -188,19 +160,8 @@ public TestResult Verify() { if (test.Contains(knownError)) { - try - { - File.Delete(compileResult.AssemblyFullPath); - } - catch (Exception) - { - // ignore errors - } -#if UNREACHABLE - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-knownerrors"); - -#endif - return TheTestResult(compileResult.AssemblyFullPath, TestResult.KnownErrors); + return TheTestResult(compileResult.AssemblyFullPath, test.StartsWith("System.OverflowException:") ? + TestResult.Overflow : TestResult.DivideByZero); } } } @@ -239,9 +200,10 @@ private TestResult TheTestResult(string assemblyPath, TestResult result) { File.Delete(assemblyPath); } - catch (Exception) + catch (Exception ex) { // ignore errors + Console.WriteLine($"Error deleting {assemblyPath} : {ex}"); } return result; } @@ -289,7 +251,7 @@ private void SaveTestCase( fileContents.AppendLine($"// TestVars: {string.Join("|", testVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); } fileContents.AppendLine("//"); - fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); + fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().SyntaxTree.GetText().ToString()); fileContents.AppendLine("/*"); fileContents.AppendFormat("Config: {0}", Config.Name).AppendLine(); diff --git a/TestMethod.cs b/TestMethod.cs index 31ab440..c8b8f4c 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -220,27 +220,6 @@ protected virtual void PopulateMethodSignature() CurrentScope.AddLocal(paramType, paramName); } - ParameterSyntax parameterNode = Helpers.GetParameterSyntax(paramType, paramName); - if (passingWay != ParamValuePassing.None) - { - SyntaxToken passingWayToken = Token(SyntaxKind.None); - switch (passingWay) - { - //case ParamValuePassing.In: - // passingWayToken = Token(SyntaxKind.InKeyword); - // break; - case ParamValuePassing.Out: - passingWayToken = Token(SyntaxKind.OutKeyword); - break; - case ParamValuePassing.Ref: - passingWayToken = Token(SyntaxKind.RefKeyword); - break; - default: - Debug.Assert(false, "invalid value for passingway!"); - break; - } - } - parameters.Add(new MethodParam() { ParamName = paramName, From 92e0fa8292f49be509f687858210bfddd779f6f4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Sep 2021 13:15:59 -0700 Subject: [PATCH 073/149] Add missing files --- Expressions/CastExpression.cs | 23 +++++ Expressions/CreationExpression.cs | 29 ++++++ RenderContext.cs | 29 ++++++ Statements/ArbitraryCodeStatement.cs | 27 ++++++ Statements/ClassDeclStatement.cs | 34 +++++++ Statements/FieldDeclStatement.cs | 31 +++++++ Statements/MethodDeclStatement.cs | 64 ++++++++++++++ Statements/StructDeclStatement.cs | 127 +++++++++++++++++++++++++++ 8 files changed, 364 insertions(+) create mode 100644 Expressions/CastExpression.cs create mode 100644 Expressions/CreationExpression.cs create mode 100644 RenderContext.cs create mode 100644 Statements/ArbitraryCodeStatement.cs create mode 100644 Statements/ClassDeclStatement.cs create mode 100644 Statements/FieldDeclStatement.cs create mode 100644 Statements/MethodDeclStatement.cs create mode 100644 Statements/StructDeclStatement.cs diff --git a/Expressions/CastExpression.cs b/Expressions/CastExpression.cs new file mode 100644 index 0000000..39fd338 --- /dev/null +++ b/Expressions/CastExpression.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. + +namespace Antigen.Expressions +{ + public class CastExpression : Expression + { + public readonly Expression Expression; + public readonly Tree.ValueType ToType; + + public CastExpression(TestCase testCase, Expression expr, Tree.ValueType toType) : base(testCase) + { + Expression = expr; + ToType = toType; + } + + public override string ToString() + { + return $"(({ToType}) ({Expression}))"; + } + } +} diff --git a/Expressions/CreationExpression.cs b/Expressions/CreationExpression.cs new file mode 100644 index 0000000..5651ce7 --- /dev/null +++ b/Expressions/CreationExpression.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Expressions +{ + public class CreationExpression : Expression + { + public readonly string TypeName; + public readonly List Arguments; + + public CreationExpression(TestCase testCase, string typeName, List arguments) : base(testCase) + { + TypeName = typeName; + Arguments = arguments; + } + + public override string ToString() + { + return Arguments != null ? $"new {TypeName}({string.Join(",", Arguments)})" : $"new {TypeName}()"; + } + } +} diff --git a/RenderContext.cs b/RenderContext.cs new file mode 100644 index 0000000..8f11417 --- /dev/null +++ b/RenderContext.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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen +{ + public class RenderContext + { + public TextWriter Stream; + + public void Write(string s, params object[] args) + { + Stream.Write(s, args); + } + + public void WriteLine(string s, params object[] args) + { + Stream.Write(s, args); + Stream.WriteLine(""); + } + } +} diff --git a/Statements/ArbitraryCodeStatement.cs b/Statements/ArbitraryCodeStatement.cs new file mode 100644 index 0000000..49f378f --- /dev/null +++ b/Statements/ArbitraryCodeStatement.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class ArbitraryCodeStatement : Statement + { + public readonly string Code; + + public ArbitraryCodeStatement(TestCase testCase, string code) : base(testCase) + { + Code = code; + } + + public override string ToString() + { + return Code; + } + } +} diff --git a/Statements/ClassDeclStatement.cs b/Statements/ClassDeclStatement.cs new file mode 100644 index 0000000..94cde5c --- /dev/null +++ b/Statements/ClassDeclStatement.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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class ClassDeclStatement : Statement + { + public readonly string ClassName; + public readonly List ClassMembers; + + public ClassDeclStatement(TestCase testCase, string className, List classMembers) : base(testCase) + { + ClassName = className; + ClassMembers = classMembers; + } + + public override string ToString() + { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.AppendFormat("public class {0} {{", ClassName).AppendLine(); + ClassMembers.ForEach(member => strBuilder.AppendLine(member.ToString())); + strBuilder.AppendLine("}"); + + return strBuilder.ToString(); + } + } +} diff --git a/Statements/FieldDeclStatement.cs b/Statements/FieldDeclStatement.cs new file mode 100644 index 0000000..cb03f1a --- /dev/null +++ b/Statements/FieldDeclStatement.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.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Expressions; + +namespace Antigen.Statements +{ + public class FieldDeclStatement : VarDeclStatement + { + public readonly bool IsStatic; + public readonly bool IsProperty; + + public FieldDeclStatement(TestCase testCase, Tree.ValueType typeName, string variableName, Expression rhs, bool isStatic, bool isProperty = false) : base(testCase, typeName, variableName, rhs) + { + IsStatic = isStatic; + IsProperty = isProperty; + } + + public override string ToString() + { + string qualifiers = IsStatic ? "static" : string.Empty; + return $"{qualifiers} {base.ToString()}"; + } + } +} diff --git a/Statements/MethodDeclStatement.cs b/Statements/MethodDeclStatement.cs new file mode 100644 index 0000000..db1975e --- /dev/null +++ b/Statements/MethodDeclStatement.cs @@ -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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Antigen.Statements +{ + public class MethodDeclStatement : Statement + { + public readonly MethodSignature MethodSignature; + public readonly List MethodBody; + + public MethodDeclStatement(TestCase testCase, MethodSignature methodSignature, List methodBody) : base(testCase) + { + MethodSignature = methodSignature; + MethodBody = methodBody; + } + + public override string ToString() + { + StringBuilder strBuilder = new StringBuilder(); + + if (MethodSignature.IsNoInline) + { + strBuilder.AppendLine("[MethodImpl(MethodImplOptions.NoInlining)]"); + } + + var methodName = MethodSignature.MethodName; + var returnType = MethodSignature.ReturnType; + var parameters = MethodSignature.Parameters.Select(p => + { + string parameter; + if (p.PassingWay == ParamValuePassing.Out) + { + parameter = "out "; + } + else if (p.PassingWay == ParamValuePassing.Ref) + { + parameter = "ref "; + } + else + { + parameter = ""; + } + parameter += $"{p.ParamType} {p.ParamName}"; + return parameter; + }); + + strBuilder.AppendFormat("public {0} {1}({2})", returnType, methodName, string.Join(", ", parameters)).AppendLine(); + strBuilder.AppendLine("{"); + strBuilder.AppendLine("unchecked {"); + MethodBody.ForEach(stmt => strBuilder.AppendLine(stmt.ToString())); + strBuilder.AppendLine("}"); + strBuilder.AppendLine("}"); + + return strBuilder.ToString(); + } + } +} diff --git a/Statements/StructDeclStatement.cs b/Statements/StructDeclStatement.cs new file mode 100644 index 0000000..8a1399e --- /dev/null +++ b/Statements/StructDeclStatement.cs @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +//using Microsoft.CodeAnalysis.CSharp.Syntax; +//using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + + +namespace Antigen.Statements +{ + public class StructDeclStatement : Statement + { + public readonly string StructName; + public readonly List StructFields; + public readonly List NestedStructs; + + public StructDeclStatement(TestCase testCase, string structName, List structFields, List nestedStructs) : base(testCase) + { + StructName = structName; + StructFields = structFields; + NestedStructs = nestedStructs; + } + + public override string ToString() + { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.AppendFormat("public struct {0} {{", StructName).AppendLine(); + // First define all the nested structs + NestedStructs.ForEach(ns => strBuilder.AppendFormat("{0}", ns).AppendLine()); + + // Next define all the fields + strBuilder.AppendLine(string.Join(Environment.NewLine, StructFields)); + strBuilder.AppendLine("}"); + + return strBuilder.ToString(); + } + + ///// + ///// Generate structs in this class + ///// + ///// + //private static List GenerateStructs() + //{ + // List structs = new List(); + + // for (int structIndex = 1; structIndex <= TC.Config.StructCount; structIndex++) + // { + // string structName = $"S{structIndex}"; + // var (structDecl, fields) = GenerateStruct(structName, structName, structIndex, 1); + // structs.Add(structDecl); + // CurrentScope.AddStructType(structName, fields); + // } + + // (MemberDeclarationSyntax, List) GenerateStruct(string structName, string structType, int structIndex, int depth) + // { + // StructDeclarationSyntax structDeclaration = StructDeclaration(structName) + // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); + + // List fieldsTree = new List(); + // List fieldsMetadata = new List(); + // int fieldCount = PRNG.Next(1, TC.Config.StructFieldCount); + // for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) + // { + // if (PRNG.Decide(TC.Config.NestedStructProbability) && depth < TC.Config.NestedStructDepth) + // { + // string nestedStructName = $"S{structIndex}_D{depth}_F{fieldIndex}"; + // string nestedStructType = structType + "." + nestedStructName; + // var (structDecl, childFields) = GenerateStruct(nestedStructName, nestedStructType, structIndex, depth + 1); + // fieldsTree.Add(structDecl); + // CurrentScope.AddStructType(nestedStructType, childFields); + // structName = nestedStructName; + // continue; + // } + + // Tree.ValueType fieldType; + // string fieldName; + + // if (PRNG.Decide(TC.Config.StructFieldTypeProbability) && CurrentScope.NumOfStructTypes > 0) + // { + // fieldType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; + // } + // else + // { + // fieldType = GetASTUtils().GetRandomExprType(); + // } + + // fieldName = Helpers.GetVariableName(fieldType, fieldIndex); + // fieldsTree.Add(FieldDeclaration(Helpers.GetVariableDeclaration(fieldType, fieldName)).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); + // fieldsMetadata.Add(new StructField(fieldType, fieldName)); + // } + + // return (structDeclaration.WithMembers(fieldsTree.ToSyntaxList()), fieldsMetadata); + // } + + // return structs; + //} + } + + /// + /// Represents a field present in a struct. This is useful to + /// expand the fully qualifier name of a field present inside a + /// nested struct. + /// + public struct StructField + { + public string FieldName; + public Tree.ValueType FieldType; + public string Accessor; + + public StructField(Tree.ValueType type, string name, string accessor = "public") + { + FieldType = type; + FieldName = name; + Accessor = accessor; + } + + public override string ToString() + { + return $"{Accessor} {FieldType} {FieldName};"; + } + } +} From 062708bc6311e49293d08782edc49b2910051620 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 20 Sep 2021 23:05:40 -0700 Subject: [PATCH 074/149] Just run 500 test cases --- Config/antigen.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config/antigen.json b/Config/antigen.json index 3ef88df..fe4bce1 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,7 +1,7 @@ { "Seed": -1, "OutputDirectory": ".", - "NumTestCases": 1000, + "NumTestCases": 500, "HoursToRun": 10, "BaselineEnvVars": [ { From a6e9f11720cb54fa6402b661b2b5641b0bf32d07 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 16:28:29 -0700 Subject: [PATCH 075/149] Add Command line parsing --- Antigen.csproj | 1 + Config/RunOptions.cs | 2 +- Config/antigen.json | 1404 +++++++++++++++++++++--------------------- Program.cs | 84 ++- RenderContext.cs | 29 - 5 files changed, 771 insertions(+), 749 deletions(-) delete mode 100644 RenderContext.cs diff --git a/Antigen.csproj b/Antigen.csproj index afd3f05..43c10a9 100644 --- a/Antigen.csproj +++ b/Antigen.csproj @@ -8,6 +8,7 @@ + diff --git a/Config/RunOptions.cs b/Config/RunOptions.cs index d776409..d9aded0 100644 --- a/Config/RunOptions.cs +++ b/Config/RunOptions.cs @@ -22,7 +22,7 @@ public class RunOptions public long NumTestCases = 0; // Duration to execute tests for (overrides number specified in each XML config file) - public int HoursToRun = 0; + public int RunDuration = 0; [NonSerialized()] public string CoreRun = null; diff --git a/Config/antigen.json b/Config/antigen.json index fe4bce1..1969862 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,707 +1,707 @@ { - "Seed": -1, - "OutputDirectory": ".", - "NumTestCases": 500, - "HoursToRun": 10, - "BaselineEnvVars": [ - { - "Name": "Default", - "Variables": [ - { - "Name": "JITMinOpts", - "Weight": 1.0, - "Values": [ - "1" - ] - }, - { - "Name": "TieredCompilation", - "Weight": 1.0, - "Values": [ - "1" - ] - } - ] + "Seed": -1, + "OutputDirectory": ".", + "NumTestCases": 500, + "RunDuration": 2147483647, + "BaselineEnvVars": [ + { + "Name": "Default", + "Variables": [ + { + "Name": "JITMinOpts", + "Weight": 1.0, + "Values": [ + "1" + ] + }, + { + "Name": "TieredCompilation", + "Weight": 1.0, + "Values": [ + "1" + ] } - ], - "TestEnvVars": [ - { - "Name": "Default", - "Weight": 0, - "Variables": [ - { - "Name": "JitCloneLoops", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitAlignLoops", - "Weight": 0.02, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitAlignLoopAdaptive", - "Weight": 0.01, - "Values": [ - "1" - ] - }, - { - "Name": "JitAlignLoopMinBlockWeight", - "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "10", - "20" - ] - }, - { - "Name": "JitDoubleAlign", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableDevirtualization", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableLateDevirtualization", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitForceFallback", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JITInlineDepth", - "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "10", - "20" - ] - }, - { - "Name": "JitNoCMOV", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoCSE", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoCSE2", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoForceFallback", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoHoist", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoInline", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoMemoryBarriers", - "Weight": 0.02, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoStructPromotion", - "Weight": 0.02, - "Values": [ - "0", - "1", - "2" - ] - }, - { - "Name": "JitNoUnroll", - "Weight": 0.02, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitStackAllocToLocalSize", - "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "4", - "10", - "16", - "100" - ] - }, - { - "Name": "JitSkipArrayBoundCheck", - "Weight": 0.0002, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitSlowDebugChecksEnabled", - "Weight": 0.002, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitSplitFunctionSize", - "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "4", - "10", - "16", - "100" - ] - }, - { - "Name": "JitStackChecks", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "InjectFault", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoRngChks", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableNoWayAssert", - "Weight": 0.01, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitAggressiveInlining", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitMaxLocalsToTrack", - "Weight": 0.05, - "Values": [ - "0", - "0x10", - "0x400", - "0x800", - "0x1000" - ] - }, - { - "Name": "JitDoAssertionProp", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoCopyProp", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoEarlyProp", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoLoopHoisting", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoLoopInversion", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoRangeAnalysis", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoRedundantBranchOpts", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoSsa", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitDoValueNumber", - "Weight": 0.05, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitOptRepeat", - "Weight": 0.0005, - "Values": [ - "*" - ] - }, - { - "Name": "JitOptRepeatCount", - "Weight": 0.0003, - "Values": [ - "1", - "2", - "5" - ] - }, - { - "Name": "TailCallLoopOpt", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "FastTailCalls", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableFinallyCloning", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableRemoveEmptyTry", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitEnableGuardedDevirtualization", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitExpandCallsEarly", - "Weight": 0.03, - "Values": [ - "0", - "1" - ] - } - ] - }, - { - "Name": "JitStress", - "Weight": 0.3, - "Variables": [ - { - "Name": "JitStress", - "Weight": 0.04, - "Values": [ - "0", - "1", - "2" - ] - }, - { - "Name": "TailcallStress", - "Weight": 0.02, - "Values": [ - "0", - "1" - ] - } - ] - }, - { - "Name": "JitStressRegs", - "Weight": 0.3, - "Variables": [ - { - "Name": "JitStressRegs", - "Weight": 0.04, - "Values": [ - "0", - "1", - "2", - "3", - "4", - "8", - "0x10", - "0x80", - "0x1000" - ] - } - ] - }, - { - "Name": "GCStress", - "Weight": 0.3, - "Variables": [ - { - "Name": "GCStress", - "Weight": 0.04, - "Values": [ - "0x3", - "0xC", - "0xF" - ] - } - ] - }, - { - "Name": "Hardware", - "Weight": 0.2, - "Variables": [ - { - "Name": "EnableAES", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableAVX", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableAVX2", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableBMI1", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableBMI2", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableFMA", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableHWIntrinsic", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableIncompleteISAClass", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableLZCNT", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnablePCLMULQDQ", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnablePOPCNT", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE2", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE3", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE3_4", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE41", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSE42", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "EnableSSSE3", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - }, - { - "Name": "FeatureSIMD", - "Weight": "0.02", - "Values": [ - "0", - "1" - ] - } - ] + ] + } + ], + "TestEnvVars": [ + { + "Name": "Default", + "Weight": 0, + "Variables": [ + { + "Name": "JitCloneLoops", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAlignLoops", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAlignLoopAdaptive", + "Weight": 0.01, + "Values": [ + "1" + ] + }, + { + "Name": "JitAlignLoopMinBlockWeight", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "10", + "20" + ] + }, + { + "Name": "JitDoubleAlign", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableDevirtualization", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableLateDevirtualization", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitForceFallback", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JITInlineDepth", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "10", + "20" + ] + }, + { + "Name": "JitNoCMOV", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoCSE", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoCSE2", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoForceFallback", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoHoist", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoInline", + "Weight": 0.04, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoMemoryBarriers", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoStructPromotion", + "Weight": 0.02, + "Values": [ + "0", + "1", + "2" + ] + }, + { + "Name": "JitNoUnroll", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitStackAllocToLocalSize", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "4", + "10", + "16", + "100" + ] + }, + { + "Name": "JitSkipArrayBoundCheck", + "Weight": 0.0002, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitSlowDebugChecksEnabled", + "Weight": 0.002, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitSplitFunctionSize", + "Weight": 0.01, + "Values": [ + "0", + "1", + "2", + "4", + "10", + "16", + "100" + ] + }, + { + "Name": "JitStackChecks", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "InjectFault", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitNoRngChks", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableNoWayAssert", + "Weight": 0.01, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitAggressiveInlining", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitMaxLocalsToTrack", + "Weight": 0.05, + "Values": [ + "0", + "0x10", + "0x400", + "0x800", + "0x1000" + ] + }, + { + "Name": "JitDoAssertionProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoCopyProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoEarlyProp", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoLoopHoisting", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoLoopInversion", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoRangeAnalysis", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoRedundantBranchOpts", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoSsa", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitDoValueNumber", + "Weight": 0.05, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitOptRepeat", + "Weight": 0.0005, + "Values": [ + "*" + ] + }, + { + "Name": "JitOptRepeatCount", + "Weight": 0.0003, + "Values": [ + "1", + "2", + "5" + ] + }, + { + "Name": "TailCallLoopOpt", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "FastTailCalls", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableFinallyCloning", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableRemoveEmptyTry", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitEnableGuardedDevirtualization", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] + }, + { + "Name": "JitExpandCallsEarly", + "Weight": 0.03, + "Values": [ + "0", + "1" + ] } - ], - "Configs": [ - { - "Name": "Basic", - "MaxStmtDepth": 2, - "MaxExprDepth": 3, - "MethodCount": 5, - "TryCatchFinallyStatementWeight": 0 - }, - { - "Name": "Structs", - "StructCount": 5, - "StructFieldCount": 5, - "NestedStructDepth": 3, - "NestedStructProbability": 0.4, - "StructFieldTypeProbability": 0.5, - "StructAliasProbability": 0.5, - "StructUsageProbability": 0.8 - }, - { - "Name": "MethodCalls", - "MethodCount": 100, - "MaxStatementCount": 3, - "MaxStmtDepth": 2, - "MaxExprDepth": 3, - "MethodCallStatementWeight": 0.7, - "MethodCallWeight": "0.4", - "ParamPassingRefProbability": 0.5, - "ParamPassingOutProbability": 0.4, - "LeafMethodsNoInlineProbability": 0.8, - "MaxMethodParametersCount": 20, - "StructUsageProbability": 0.7 - }, - { - "Name": "Full", - "MaxStmtDepth": 5, - "MaxExprDepth": 5, - "VariablesCount": 10, - "MethodCount": 5, - "MaxStatementCount": 10, - "TryCatchFinallyStatementWeight": 0.03, - "LocalVariablesLogProbability": 1.0 - }, - { - "Name": "ExceptionHandler", - "MaxStmtDepth": 5, - "MethodCount": 2, - "TryCatchFinallyStatementWeight": 0.5, - "CatchClausesCount": 5, - "FinallyClauseProbability": 0.7 - }, - { - "Name": "Loops", - "MaxStmtDepth": 5, - "MethodCount": 2, - "ForStatementWeight": 0.5, - "DoWhileStatementWeight": 0.5, - "WhileStatementWeight": 0.5, - "LoopParametersRemovalProbability": 0.4, - "LoopForwardProbability": 0.5, - "LoopStartFromInvariantProbabilty": 0.3, - "LoopStepPreBreakCondProbability": 0.6, - "UseLoopInvariantVariableProbability": 1.0, - "AllowLoopCondAtEnd": false - }, - { - "Name": "ControlFlow", - "MaxCaseCounts": 10, - "MaxStmtDepth": 6, - "MaxStatementCount": 4, - "IfElseStatementWeight": 0.4, - "ForStatementWeight": 0.5, - "DoWhileStatementWeight": 0.5, - "WhileStatementWeight": 0.5, - "SwitchStatementWeight": 0.45 + ] + }, + { + "Name": "JitStress", + "Weight": 0.3, + "Variables": [ + { + "Name": "JitStress", + "Weight": 0.04, + "Values": [ + "0", + "1", + "2" + ] + }, + { + "Name": "TailcallStress", + "Weight": 0.02, + "Values": [ + "0", + "1" + ] + } + ] + }, + { + "Name": "JitStressRegs", + "Weight": 0.3, + "Variables": [ + { + "Name": "JitStressRegs", + "Weight": 0.04, + "Values": [ + "0", + "1", + "2", + "3", + "4", + "8", + "0x10", + "0x80", + "0x1000" + ] + } + ] + }, + { + "Name": "GCStress", + "Weight": 0.3, + "Variables": [ + { + "Name": "GCStress", + "Weight": 0.04, + "Values": [ + "0x3", + "0xC", + "0xF" + ] + } + ] + }, + { + "Name": "Hardware", + "Weight": 0.2, + "Variables": [ + { + "Name": "EnableAES", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableAVX", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableAVX2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableBMI1", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableBMI2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableFMA", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableHWIntrinsic", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableIncompleteISAClass", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableLZCNT", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnablePCLMULQDQ", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnablePOPCNT", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE2", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE3", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE3_4", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE41", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSE42", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "EnableSSSE3", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] + }, + { + "Name": "FeatureSIMD", + "Weight": "0.02", + "Values": [ + "0", + "1" + ] } - ] + ] + } + ], + "Configs": [ + { + "Name": "Basic", + "MaxStmtDepth": 2, + "MaxExprDepth": 3, + "MethodCount": 5, + "TryCatchFinallyStatementWeight": 0 + }, + { + "Name": "Structs", + "StructCount": 5, + "StructFieldCount": 5, + "NestedStructDepth": 3, + "NestedStructProbability": 0.4, + "StructFieldTypeProbability": 0.5, + "StructAliasProbability": 0.5, + "StructUsageProbability": 0.8 + }, + { + "Name": "MethodCalls", + "MethodCount": 100, + "MaxStatementCount": 3, + "MaxStmtDepth": 2, + "MaxExprDepth": 3, + "MethodCallStatementWeight": 0.7, + "MethodCallWeight": "0.4", + "ParamPassingRefProbability": 0.5, + "ParamPassingOutProbability": 0.4, + "LeafMethodsNoInlineProbability": 0.8, + "MaxMethodParametersCount": 20, + "StructUsageProbability": 0.7 + }, + { + "Name": "Full", + "MaxStmtDepth": 5, + "MaxExprDepth": 5, + "VariablesCount": 10, + "MethodCount": 5, + "MaxStatementCount": 10, + "TryCatchFinallyStatementWeight": 0.03, + "LocalVariablesLogProbability": 1.0 + }, + { + "Name": "ExceptionHandler", + "MaxStmtDepth": 5, + "MethodCount": 2, + "TryCatchFinallyStatementWeight": 0.5, + "CatchClausesCount": 5, + "FinallyClauseProbability": 0.7 + }, + { + "Name": "Loops", + "MaxStmtDepth": 5, + "MethodCount": 2, + "ForStatementWeight": 0.5, + "DoWhileStatementWeight": 0.5, + "WhileStatementWeight": 0.5, + "LoopParametersRemovalProbability": 0.4, + "LoopForwardProbability": 0.5, + "LoopStartFromInvariantProbabilty": 0.3, + "LoopStepPreBreakCondProbability": 0.6, + "UseLoopInvariantVariableProbability": 1.0, + "AllowLoopCondAtEnd": false + }, + { + "Name": "ControlFlow", + "MaxCaseCounts": 10, + "MaxStmtDepth": 6, + "MaxStatementCount": 4, + "IfElseStatementWeight": 0.4, + "ForStatementWeight": 0.5, + "DoWhileStatementWeight": 0.5, + "WhileStatementWeight": 0.5, + "SwitchStatementWeight": 0.45 + } + ] } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 65b3694..031f436 100644 --- a/Program.cs +++ b/Program.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Antigen.Config; using Antigen.Trimmer; +using CommandLine; namespace Antigen { @@ -14,7 +15,7 @@ class Program { static readonly object s_spinLock = new object(); private static readonly RunOptions s_runOptions = RunOptions.Initialize(); - private static readonly Dictionary s_stats = new Dictionary() + private static readonly Dictionary s_stats = new() { { TestResult.RoslynException, 0 }, { TestResult.CompileError, 0 }, @@ -27,29 +28,41 @@ class Program }; private static int s_testId = 0; - private static bool done = false; - private static readonly DateTime s_StartTime = DateTime.Now; + private static readonly DateTime s_startTime = DateTime.Now; - static void Main(string[] args) + static int Main(string[] args) + { + return Parser.Default.ParseArguments(args).MapResult(Run, err => 1); + } + + private static int Run(CommandLineOptions opts) { try { PRNG.Initialize(s_runOptions.Seed); - s_runOptions.CoreRun = args[0]; + s_runOptions.CoreRun = opts.CoreRunPath; + s_runOptions.OutputDirectory = opts.IssuesFolder; + if (opts.NumTestCases > 0) + { + s_runOptions.NumTestCases = opts.NumTestCases; + } + + if (opts.RunDuration > 0) + { + s_runOptions.RunDuration = opts.RunDuration; + } if (!File.Exists(s_runOptions.CoreRun)) { - throw new Exception($"{s_runOptions.CoreRun} doesn't exist"); + throw new FileNotFoundException($"{s_runOptions.CoreRun} doesn't exist"); } - s_runOptions.OutputDirectory = args[1]; if (!Directory.Exists(s_runOptions.OutputDirectory)) { - Console.WriteLine($"Creating {s_runOptions.OutputDirectory}"); Directory.CreateDirectory(s_runOptions.OutputDirectory); } - //// trimmer + // trimmer //if (args.Length > 1) //{ // string testCaseToTrim = args[1]; @@ -57,8 +70,8 @@ static void Main(string[] args) // testTrimmer.Trim(); // return; //} - Parallel.For(0, 2, (p) => RunTest()); + Console.WriteLine($"Executed {s_testId} test cases."); } catch (OutOfMemoryException oom) @@ -73,21 +86,43 @@ static void Main(string[] args) Console.WriteLine($" Total processor time : {myProcess.TotalProcessorTime}"); Console.WriteLine($" Paged system memory size : {myProcess.PagedSystemMemorySize64}"); Console.WriteLine($" Paged memory size : {myProcess.PagedMemorySize64}"); + return 1; } + return 0; } private static int GetNextTestId() { lock (s_spinLock) { + return ++s_testId; + } + } + + /// + /// Are we done yet? + /// + private static bool Done + { + get + { + if ((DateTime.Now - s_startTime).Minutes >= s_runOptions.RunDuration) + { + return true; + } if (s_testId >= s_runOptions.NumTestCases) { - done = true; + return true; } - return ++s_testId; + + return false; } } + /// + /// Save the result. + /// + /// private static void SaveResult(Dictionary localStats) { lock (s_spinLock) @@ -123,18 +158,18 @@ static void RunTest() { TestResult.OOM, 0 }, }; - while (!done) + while (!Done) { - int currTestId = GetNextTestId(); - TestCase testCase = new TestCase(currTestId, s_runOptions); + var currTestId = GetNextTestId(); + var testCase = new TestCase(currTestId, s_runOptions); testCase.Generate(); - TestResult result = testCase.Verify(); + var result = testCase.Verify(); Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", currTestId, testCase.Config.Name, Enum.GetName(typeof(TestResult), result), (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, - (DateTime.Now - s_StartTime).ToString()); + (DateTime.Now - s_startTime).ToString()); localStats[result]++; @@ -148,4 +183,19 @@ static void RunTest() } } } + + public class CommandLineOptions + { + [Option(shortName: 'c', longName: "CoreRun", Required = true, HelpText = "Path to CoreRun/CoreRun.exe.")] + public string CoreRunPath { get; set; } + + [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where issues will be copied.")] + public string IssuesFolder { get; set; } + + [Option(shortName: 'n', longName: "NumTestCases", Required = false, HelpText = "Number of test cases to execute. By default, 1000.")] + public int NumTestCases { get; set; } + + [Option(shortName: 'd', longName: "RunDuration", Required = false, HelpText = "Duration in minutes to run. By default until NumTestCases, but if Duration is given, will override the NumTestCases.")] + public int RunDuration { get; set; } + } } diff --git a/RenderContext.cs b/RenderContext.cs deleted file mode 100644 index 8f11417..0000000 --- a/RenderContext.cs +++ /dev/null @@ -1,29 +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.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Antigen -{ - public class RenderContext - { - public TextWriter Stream; - - public void Write(string s, params object[] args) - { - Stream.Write(s, args); - } - - public void WriteLine(string s, params object[] args) - { - Stream.Write(s, args); - Stream.WriteLine(""); - } - } -} From 7b448acf3ca00e08bf17e73b8f10d84a59d6a6e3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 16:29:18 -0700 Subject: [PATCH 076/149] Add TIMEOUT check --- TestCase.cs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/TestCase.cs b/TestCase.cs index 6e12b77..3b07558 100644 --- a/TestCase.cs +++ b/TestCase.cs @@ -71,8 +71,6 @@ public enum CompilationType new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), }; - private static readonly ConcurrentDictionary _variableExpressions = new(); - //private List classesList; //private List methodsList; //private List propertiesList; @@ -137,10 +135,15 @@ public TestResult Verify() // Execute test first and see if we have any errors/asserts var test = s_testRunner.Execute(compileResult, testVariables, 30); - var testAssertion = RslnUtilities.ParseAssertionError(test); + + // If timeout, skip + if (test == "TIMEOUT") + { + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + } // If OOM, skip - if (test.Contains("Out of memory")) + else if (test.Contains("Out of memory")) { #if UNREACHABLE SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-oom"); @@ -148,8 +151,11 @@ public TestResult Verify() #endif return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); } + + var testAssertion = RslnUtilities.ParseAssertionError(test); + // If test assertion - else if (!string.IsNullOrEmpty(testAssertion)) + if (!string.IsNullOrEmpty(testAssertion)) { SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); @@ -167,18 +173,26 @@ public TestResult Verify() } string baseline = s_testRunner.Execute(compileResult, baselineVariables, 30); - string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); + + // If timeout, skip + if (baseline == "TIMEOUT") + { + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + } // If OOM, ignore this diff - if (baseline.Contains("Out of memory")) + else if (baseline.Contains("Out of memory")) { #if UNREACHABLE SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, "Out of memory", $"{Name}-base-oom"); ; #endif return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); } + + string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); + // Is there assertion in baseline? - else if (!string.IsNullOrEmpty(baselineAssertion)) + if (!string.IsNullOrEmpty(baselineAssertion)) { SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); From eb410aed4252fba30af5b0219d02b0da635576bb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 16:29:49 -0700 Subject: [PATCH 077/149] Rename MethodScope to FunctionScope --- TestMethod.cs | 4 ++-- Tree/Scope.cs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/TestMethod.cs b/TestMethod.cs index c8b8f4c..384e59f 100644 --- a/TestMethod.cs +++ b/TestMethod.cs @@ -71,7 +71,7 @@ protected TestMethod(TestClass enclosingClass, string methodName) { _testClass = enclosingClass; Name = methodName; - MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); + MethodScope = new Scope(enclosingClass.TC, ScopeKind.MethodScope, enclosingClass.ClassScope); } /// @@ -84,7 +84,7 @@ public TestMethod(TestClass enclosingClass, string methodName, bool isMainInvoca { _testClass = enclosingClass; Name = methodName; - MethodScope = new Scope(enclosingClass.TC, ScopeKind.FunctionScope, enclosingClass.ClassScope); + MethodScope = new Scope(enclosingClass.TC, ScopeKind.MethodScope, enclosingClass.ClassScope); _isMainInvocation = isMainInvocation; _valuePassing = new() { diff --git a/Tree/Scope.cs b/Tree/Scope.cs index e644cbd..463fd57 100644 --- a/Tree/Scope.cs +++ b/Tree/Scope.cs @@ -7,15 +7,14 @@ namespace Antigen.Tree { /* * Scopes need information about their "kind" - which construct pushed a new scope - * This information is used in parts of ExprGen that need to do backtracking - ex. + * This information is used in parts of Antigen that need to do backtracking - ex. * the logic behind generating new label names */ public enum ScopeKind { ConditionalScope, //introduced by any "conditional" construct - try/catch, loops, if, switch LoopScope, //introduced by any loops - GetterSetterScope, //introduced by getters, setters and other ImplicitCallKind - FunctionScope, //default, scope introduced by a new function + MethodScope, //default, scope introduced by a method BracesScope //introduced by { } } @@ -53,7 +52,7 @@ public class Scope public Scope(TestCase tc) { TestCase = tc; - ScopeType = ScopeKind.FunctionScope; + ScopeType = ScopeKind.MethodScope; } public Scope(TestCase tc, ScopeKind t, Scope parentScope) From 32bbb65aa436dfc85757de032e355a831932e709 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 16:30:06 -0700 Subject: [PATCH 078/149] Changes to trimmer --- .../Statements/ConsoleLogStmtRemoval.cs | 2 +- Trimmer/TestTrimmer.cs | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs index 8764d40..00edab6 100644 --- a/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs @@ -22,7 +22,7 @@ public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax no { if (removeAll) { - if (node.ToFullString().Trim().StartsWith("Console.WriteLine")) + if ((node.ToFullString().Trim().StartsWith("Console.WriteLine")) || (node.ToFullString().Trim().StartsWith("Log"))) { isAnyNodeVisited = true; return null; diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 5530f4e..d25ce72 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -48,22 +48,23 @@ public TestTrimmer(string testFileToTrim, RunOptions runOptions) /// private void ParseEnvironment() { - var fileContents = File.ReadAllText(_testFileToTrim); - string[] fileContentLines = fileContents.Split(Environment.NewLine); + var fileContents = File.ReadAllText(_testFileToTrim.Replace(Environment.NewLine, "\n")); + string[] fileContentLines = fileContents.Split("\n"); _originalTestAssertion = RslnUtilities.ParseAssertionError(fileContents); foreach (var line in fileContentLines) { - if (line.StartsWith("// BaselineVars: ")) + var lineContent = line.Trim(); + if (lineContent.StartsWith("// BaselineVars: ")) { - var baselineContents = line.Replace("// BaselineVars: ", string.Empty); + var baselineContents = lineContent.Replace("// BaselineVars: ", string.Empty).Trim(); _baselineVariables = baselineContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); continue; } - else if (line.StartsWith("// TestVars: ")) + else if (lineContent.StartsWith("// TestVars: ")) { - var testContents = line.Replace("// TestVars: ", string.Empty); + var testContents = lineContent.Replace("// TestVars: ", string.Empty).Trim(); _testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); return; } @@ -91,7 +92,7 @@ public void TrimTree() do { trimmedAtleastOne = false; - trimmedAtleastOne |= TrimEnvVars(); + //trimmedAtleastOne |= TrimEnvVars(); trimmedAtleastOne |= TrimStatements(); trimmedAtleastOne |= TrimExpressions(); @@ -180,11 +181,15 @@ public bool TrimExpressions() public bool TrimEnvVars() { bool trimmedAtleastOne = false; - SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); + SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText( _testFileToTrim)).GetRoot(); var keys = _testVariables.Keys.ToList(); foreach(var envVar in keys) { + if (envVar.Contains("AltJit")) + { + continue; + } string value = _testVariables[envVar]; _testVariables.Remove(envVar); @@ -219,6 +224,10 @@ private bool Trim(List trimmerList) bool trimmedAtleastOne = false; bool trimmedInCurrIter; TestResult expectedResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; + if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) != expectedResult) + { + return false; + } do { @@ -373,7 +382,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< //} string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, EnvVarOptions.BaseLineVars(), 10); - string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 10); + string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 40); TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; @@ -432,7 +441,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< { foreach (var envVars in baselineEnvVars) { - fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); + fileContents.AppendFormat("set {0}={1}", envVars.Key, envVars.Value).AppendLine(); } } fileContents.AppendLine(); @@ -444,7 +453,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine(); foreach (var envVars in testEnvVars) { - fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); + fileContents.AppendFormat("set {0}={1}", envVars.Key, envVars.Value).AppendLine(); } fileContents.AppendLine(); fileContents.AppendLine(currRunTestOutput); From f1b68917e47858189b0631052c5af0987f493818 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 16:30:39 -0700 Subject: [PATCH 079/149] Default num of test cases = 1000 --- Config/antigen.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config/antigen.json b/Config/antigen.json index 1969862..83245f4 100644 --- a/Config/antigen.json +++ b/Config/antigen.json @@ -1,7 +1,7 @@ { "Seed": -1, "OutputDirectory": ".", - "NumTestCases": 500, + "NumTestCases": 1000, "RunDuration": 2147483647, "BaselineEnvVars": [ { From 0e322fde8f05edc867dd5a8b944e1b479de74bde Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 18:09:02 -0700 Subject: [PATCH 080/149] Move around to create Antigen/Trimmer projects --- Antigen.sln | 8 ++- Program.cs => Antigen/Antigen.cs | 12 +--- Antigen.csproj => Antigen/Antigen.csproj | 5 ++ {Config => Antigen/Config}/ConfigOptions.cs | 4 -- {Config => Antigen/Config}/EnvVarOptions.cs | 5 -- {Config => Antigen/Config}/RunOptions.cs | 3 - {Config => Antigen/Config}/antigen.json | 0 .../Expressions}/AssignExpression.cs | 5 -- .../Expressions}/BinaryExpression.cs | 5 -- .../Expressions}/CastExpression.cs | 0 .../Expressions}/ConstantValue.cs | 3 - .../Expressions}/CreationExpression.cs | 4 -- .../Expressions}/Expression.cs | 3 +- .../Expressions}/MethodCallExpression.cs | 4 -- .../Expressions}/ParenthsizedExpression.cs | 5 -- .../Expressions}/UnaryExpression.cs | 5 -- .../Expressions}/VariableExpression.cs | 7 -- {Helpers => Antigen/Helpers}/Constants.cs | 6 -- {Helpers => Antigen/Helpers}/Literals.cs | 13 +--- {Helpers => Antigen/Helpers}/PreGenerated.cs | 4 -- .../Helpers}/VariableDeclarationHelper.cs | 8 +-- PRNG.cs => Antigen/PRNG.cs | 0 .../Statements}/ArbitraryCodeStatement.cs | 6 -- .../Statements}/AssignStatement.cs | 5 -- .../Statements}/ClassDeclStatement.cs | 3 - .../Statements}/DoWhileStatement.cs | 1 - .../Statements}/FieldDeclStatement.cs | 5 -- .../Statements}/ForStatement.cs | 1 - .../Statements}/IfElseStatement.cs | 2 - .../Statements}/LoopStatement.cs | 1 - .../Statements}/MethodCallStatement.cs | 5 -- .../Statements}/MethodDeclStatement.cs | 2 - .../Statements}/ReturnStatement.cs | 5 -- .../Statements}/Statement.cs | 3 +- .../Statements}/StructDeclStatement.cs | 2 - .../Statements}/SwitchStatement.cs | 2 - .../Statements}/TryCatchFinallyStatement.cs | 2 - .../Statements}/VarDeclStatement.cs | 5 -- .../Statements}/WhileStatement.cs | 1 - Structs.cs => Antigen/Structs.cs | 7 -- TestCase.cs => Antigen/TestCase.cs | 27 +------ TestClass.cs => Antigen/TestClass.cs | 7 -- TestMethod.cs => Antigen/TestMethod.cs | 4 +- {Tree => Antigen/Tree}/AstUtils.cs | 0 {Tree => Antigen/Tree}/Kinds.cs | 6 -- {Tree => Antigen/Tree}/Node.cs | 6 -- {Tree => Antigen/Tree}/Operators.cs | 0 {Tree => Antigen/Tree}/Scope.cs | 0 {Tree => Antigen/Tree}/Types.cs | 0 .../Expressions/AssignExprRemoval.cs | 5 -- .../Rewriters/Expressions/BinaryExpRemoval.cs | 7 +- .../Rewriters/Expressions/CastExprRemoval.cs | 6 +- .../Rewriters/Expressions/FieldExprRemoval.cs | 5 -- .../Expressions/IdentityNameExprRemoval.cs | 5 -- .../Expressions/InvocationExprRemoval.cs | 5 -- .../Expressions/LiteralExprRemoval.cs | 5 -- .../Expressions/MemberAccessExprRemoval.cs | 5 -- .../Rewriters/Expressions/ParenExprRemoval.cs | 6 +- Trimmer/Rewriters/Statements/BlockRemoval.cs | 5 -- .../Statements/ConsoleLogStmtRemoval.cs | 6 -- .../Statements/DoWhileStmtRemoval.cs | 5 -- .../Rewriters/Statements/ExprStmtRemoval.cs | 5 -- .../Rewriters/Statements/ForStmtRemoval.cs | 5 -- .../Rewriters/Statements/IfElseStmtRemoval.cs | 4 -- .../Statements/LocalDeclStmtRemoval.cs | 5 -- .../Statements/MethodDeclStmtRemoval.cs | 5 -- .../Statements/StructDeclStmtRemoval.cs | 5 -- .../Rewriters/Statements/SwitchStmtRemoval.cs | 5 -- .../Rewriters/Statements/SyntaxRewriter.cs | 5 -- .../Statements/TryCatchFinallyStmtRemoval.cs | 5 -- .../Rewriters/Statements/WhileStmtRemoval.cs | 5 -- Trimmer/TestTrimmer.cs | 71 +++++++++++++------ Trimmer/Trimmer.csproj | 18 +++++ {Helpers => Utils}/RslnUtilities.cs | 6 +- {Helpers => Utils}/TestRunner.cs | 57 ++++++++++----- 75 files changed, 130 insertions(+), 353 deletions(-) rename Program.cs => Antigen/Antigen.cs (94%) rename Antigen.csproj => Antigen/Antigen.csproj (84%) rename {Config => Antigen/Config}/ConfigOptions.cs (98%) rename {Config => Antigen/Config}/EnvVarOptions.cs (94%) rename {Config => Antigen/Config}/RunOptions.cs (95%) rename {Config => Antigen/Config}/antigen.json (100%) rename {Expressions => Antigen/Expressions}/AssignExpression.cs (81%) rename {Expressions => Antigen/Expressions}/BinaryExpression.cs (93%) rename {Expressions => Antigen/Expressions}/CastExpression.cs (100%) rename {Expressions => Antigen/Expressions}/ConstantValue.cs (98%) rename {Expressions => Antigen/Expressions}/CreationExpression.cs (90%) rename {Expressions => Antigen/Expressions}/Expression.cs (93%) rename {Expressions => Antigen/Expressions}/MethodCallExpression.cs (95%) rename {Expressions => Antigen/Expressions}/ParenthsizedExpression.cs (83%) rename {Expressions => Antigen/Expressions}/UnaryExpression.cs (90%) rename {Expressions => Antigen/Expressions}/VariableExpression.cs (80%) rename {Helpers => Antigen/Helpers}/Constants.cs (74%) rename {Helpers => Antigen/Helpers}/Literals.cs (86%) rename {Helpers => Antigen/Helpers}/PreGenerated.cs (97%) rename {Helpers => Antigen/Helpers}/VariableDeclarationHelper.cs (53%) rename PRNG.cs => Antigen/PRNG.cs (100%) rename {Statements => Antigen/Statements}/ArbitraryCodeStatement.cs (82%) rename {Statements => Antigen/Statements}/AssignStatement.cs (86%) rename {Statements => Antigen/Statements}/ClassDeclStatement.cs (94%) rename {Statements => Antigen/Statements}/DoWhileStatement.cs (98%) rename {Statements => Antigen/Statements}/FieldDeclStatement.cs (88%) rename {Statements => Antigen/Statements}/ForStatement.cs (99%) rename {Statements => Antigen/Statements}/IfElseStatement.cs (96%) rename {Statements => Antigen/Statements}/LoopStatement.cs (99%) rename {Statements => Antigen/Statements}/MethodCallStatement.cs (85%) rename {Statements => Antigen/Statements}/MethodDeclStatement.cs (97%) rename {Statements => Antigen/Statements}/ReturnStatement.cs (86%) rename {Statements => Antigen/Statements}/Statement.cs (92%) rename {Statements => Antigen/Statements}/StructDeclStatement.cs (99%) rename {Statements => Antigen/Statements}/SwitchStatement.cs (97%) rename {Statements => Antigen/Statements}/TryCatchFinallyStatement.cs (97%) rename {Statements => Antigen/Statements}/VarDeclStatement.cs (88%) rename {Statements => Antigen/Statements}/WhileStatement.cs (99%) rename Structs.cs => Antigen/Structs.cs (62%) rename TestCase.cs => Antigen/TestCase.cs (94%) rename TestClass.cs => Antigen/TestClass.cs (97%) rename TestMethod.cs => Antigen/TestMethod.cs (99%) rename {Tree => Antigen/Tree}/AstUtils.cs (100%) rename {Tree => Antigen/Tree}/Kinds.cs (85%) rename {Tree => Antigen/Tree}/Node.cs (87%) rename {Tree => Antigen/Tree}/Operators.cs (100%) rename {Tree => Antigen/Tree}/Scope.cs (100%) rename {Tree => Antigen/Tree}/Types.cs (100%) create mode 100644 Trimmer/Trimmer.csproj rename {Helpers => Utils}/RslnUtilities.cs (97%) rename {Helpers => Utils}/TestRunner.cs (80%) diff --git a/Antigen.sln b/Antigen.sln index 45a0c62..1fc6ae6 100644 --- a/Antigen.sln +++ b/Antigen.sln @@ -3,13 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30410.220 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Antigen", "Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Antigen", "Antigen\Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FA00618-BD61-41BA-9044-1A08C274AA24}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trimmer", "Trimmer\Trimmer.csproj", "{CE027BEA-870D-4821-886E-71E3F209A18B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,6 +22,10 @@ Global {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Debug|Any CPU.Build.0 = Debug|Any CPU {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Release|Any CPU.ActiveCfg = Release|Any CPU {4BA8106C-4D64-4F76-AA49-3A669AB31B82}.Release|Any CPU.Build.0 = Release|Any CPU + {CE027BEA-870D-4821-886E-71E3F209A18B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE027BEA-870D-4821-886E-71E3F209A18B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE027BEA-870D-4821-886E-71E3F209A18B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE027BEA-870D-4821-886E-71E3F209A18B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Program.cs b/Antigen/Antigen.cs similarity index 94% rename from Program.cs rename to Antigen/Antigen.cs index 031f436..10c2d76 100644 --- a/Program.cs +++ b/Antigen/Antigen.cs @@ -1,13 +1,11 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Threading.Tasks; using Antigen.Config; -using Antigen.Trimmer; using CommandLine; +using Utils; namespace Antigen { @@ -62,14 +60,6 @@ private static int Run(CommandLineOptions opts) Directory.CreateDirectory(s_runOptions.OutputDirectory); } - // trimmer - //if (args.Length > 1) - //{ - // string testCaseToTrim = args[1]; - // TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, s_runOptions); - // testTrimmer.Trim(); - // return; - //} Parallel.For(0, 2, (p) => RunTest()); Console.WriteLine($"Executed {s_testId} test cases."); diff --git a/Antigen.csproj b/Antigen/Antigen.csproj similarity index 84% rename from Antigen.csproj rename to Antigen/Antigen.csproj index 43c10a9..e513e24 100644 --- a/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -17,6 +17,11 @@ + + + + + false diff --git a/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs similarity index 98% rename from Config/ConfigOptions.cs rename to Antigen/Config/ConfigOptions.cs index a5636e8..74dd570 100644 --- a/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -1,11 +1,7 @@ using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Reflection; -using System.Xml; namespace Antigen.Config { diff --git a/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs similarity index 94% rename from Config/EnvVarOptions.cs rename to Antigen/Config/EnvVarOptions.cs index 06c6f96..febd46b 100644 --- a/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -2,11 +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; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -14,8 +11,6 @@ namespace Antigen.Config { public static class EnvVarOptions { - internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); - private static List s_baselineGroups; private static readonly List> s_baselineGroupWeight = new(); diff --git a/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs similarity index 95% rename from Config/RunOptions.cs rename to Antigen/Config/RunOptions.cs index d9aded0..32fb559 100644 --- a/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; namespace Antigen.Config diff --git a/Config/antigen.json b/Antigen/Config/antigen.json similarity index 100% rename from Config/antigen.json rename to Antigen/Config/antigen.json diff --git a/Expressions/AssignExpression.cs b/Antigen/Expressions/AssignExpression.cs similarity index 81% rename from Expressions/AssignExpression.cs rename to Antigen/Expressions/AssignExpression.cs index 216b737..440f11f 100644 --- a/Expressions/AssignExpression.cs +++ b/Antigen/Expressions/AssignExpression.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Tree; namespace Antigen.Expressions diff --git a/Expressions/BinaryExpression.cs b/Antigen/Expressions/BinaryExpression.cs similarity index 93% rename from Expressions/BinaryExpression.cs rename to Antigen/Expressions/BinaryExpression.cs index ca92492..5213ccf 100644 --- a/Expressions/BinaryExpression.cs +++ b/Antigen/Expressions/BinaryExpression.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; diff --git a/Expressions/CastExpression.cs b/Antigen/Expressions/CastExpression.cs similarity index 100% rename from Expressions/CastExpression.cs rename to Antigen/Expressions/CastExpression.cs diff --git a/Expressions/ConstantValue.cs b/Antigen/Expressions/ConstantValue.cs similarity index 98% rename from Expressions/ConstantValue.cs rename to Antigen/Expressions/ConstantValue.cs index 495c98c..0e932e5 100644 --- a/Expressions/ConstantValue.cs +++ b/Antigen/Expressions/ConstantValue.cs @@ -5,9 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Tree; namespace Antigen.Expressions diff --git a/Expressions/CreationExpression.cs b/Antigen/Expressions/CreationExpression.cs similarity index 90% rename from Expressions/CreationExpression.cs rename to Antigen/Expressions/CreationExpression.cs index 5651ce7..ad1dad1 100644 --- a/Expressions/CreationExpression.cs +++ b/Antigen/Expressions/CreationExpression.cs @@ -2,11 +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.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Antigen.Expressions { diff --git a/Expressions/Expression.cs b/Antigen/Expressions/Expression.cs similarity index 93% rename from Expressions/Expression.cs rename to Antigen/Expressions/Expression.cs index e833433..7343a4f 100644 --- a/Expressions/Expression.cs +++ b/Antigen/Expressions/Expression.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using Antigen.Tree; +using Antigen.Tree; namespace Antigen.Expressions { diff --git a/Expressions/MethodCallExpression.cs b/Antigen/Expressions/MethodCallExpression.cs similarity index 95% rename from Expressions/MethodCallExpression.cs rename to Antigen/Expressions/MethodCallExpression.cs index 05fa17f..eb55f07 100644 --- a/Expressions/MethodCallExpression.cs +++ b/Antigen/Expressions/MethodCallExpression.cs @@ -2,12 +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; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Antigen.Expressions { diff --git a/Expressions/ParenthsizedExpression.cs b/Antigen/Expressions/ParenthsizedExpression.cs similarity index 83% rename from Expressions/ParenthsizedExpression.cs rename to Antigen/Expressions/ParenthsizedExpression.cs index 04da9f4..315e9a9 100644 --- a/Expressions/ParenthsizedExpression.cs +++ b/Antigen/Expressions/ParenthsizedExpression.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Tree; namespace Antigen.Expressions diff --git a/Expressions/UnaryExpression.cs b/Antigen/Expressions/UnaryExpression.cs similarity index 90% rename from Expressions/UnaryExpression.cs rename to Antigen/Expressions/UnaryExpression.cs index 2a4b4ad..0dd34d7 100644 --- a/Expressions/UnaryExpression.cs +++ b/Antigen/Expressions/UnaryExpression.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; diff --git a/Expressions/VariableExpression.cs b/Antigen/Expressions/VariableExpression.cs similarity index 80% rename from Expressions/VariableExpression.cs rename to Antigen/Expressions/VariableExpression.cs index e3d55ed..27e164d 100644 --- a/Expressions/VariableExpression.cs +++ b/Antigen/Expressions/VariableExpression.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. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Antigen.Tree; - namespace Antigen.Expressions { public class VariableExpression : Expression diff --git a/Helpers/Constants.cs b/Antigen/Helpers/Constants.cs similarity index 74% rename from Helpers/Constants.cs rename to Antigen/Helpers/Constants.cs index 83b996d..b3a8f27 100644 --- a/Helpers/Constants.cs +++ b/Antigen/Helpers/Constants.cs @@ -2,12 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Antigen { public static class Constants diff --git a/Helpers/Literals.cs b/Antigen/Helpers/Literals.cs similarity index 86% rename from Helpers/Literals.cs rename to Antigen/Helpers/Literals.cs index 5ed7646..4cb686f 100644 --- a/Helpers/Literals.cs +++ b/Antigen/Helpers/Literals.cs @@ -1,15 +1,4 @@ -using Antigen.Config; -using Antigen.Tree; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using System.Text; namespace Antigen { diff --git a/Helpers/PreGenerated.cs b/Antigen/Helpers/PreGenerated.cs similarity index 97% rename from Helpers/PreGenerated.cs rename to Antigen/Helpers/PreGenerated.cs index bf832a4..ef0b9d3 100644 --- a/Helpers/PreGenerated.cs +++ b/Antigen/Helpers/PreGenerated.cs @@ -2,11 +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.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; //using Microsoft.CodeAnalysis.CSharp.Syntax; //using Microsoft.CodeAnalysis.CSharp; //using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; diff --git a/Helpers/VariableDeclarationHelper.cs b/Antigen/Helpers/VariableDeclarationHelper.cs similarity index 53% rename from Helpers/VariableDeclarationHelper.cs rename to Antigen/Helpers/VariableDeclarationHelper.cs index 473a5c5..1fe58a7 100644 --- a/Helpers/VariableDeclarationHelper.cs +++ b/Antigen/Helpers/VariableDeclarationHelper.cs @@ -1,10 +1,4 @@ -using Antigen.Tree; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - -namespace Antigen +namespace Antigen { public static partial class Helpers { diff --git a/PRNG.cs b/Antigen/PRNG.cs similarity index 100% rename from PRNG.cs rename to Antigen/PRNG.cs diff --git a/Statements/ArbitraryCodeStatement.cs b/Antigen/Statements/ArbitraryCodeStatement.cs similarity index 82% rename from Statements/ArbitraryCodeStatement.cs rename to Antigen/Statements/ArbitraryCodeStatement.cs index 49f378f..ca7584f 100644 --- a/Statements/ArbitraryCodeStatement.cs +++ b/Antigen/Statements/ArbitraryCodeStatement.cs @@ -2,12 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Antigen.Statements { public class ArbitraryCodeStatement : Statement diff --git a/Statements/AssignStatement.cs b/Antigen/Statements/AssignStatement.cs similarity index 86% rename from Statements/AssignStatement.cs rename to Antigen/Statements/AssignStatement.cs index 037b4d4..83fa606 100644 --- a/Statements/AssignStatement.cs +++ b/Antigen/Statements/AssignStatement.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; using Antigen.Tree; diff --git a/Statements/ClassDeclStatement.cs b/Antigen/Statements/ClassDeclStatement.cs similarity index 94% rename from Statements/ClassDeclStatement.cs rename to Antigen/Statements/ClassDeclStatement.cs index 94cde5c..e1fbf52 100644 --- a/Statements/ClassDeclStatement.cs +++ b/Antigen/Statements/ClassDeclStatement.cs @@ -2,11 +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; using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; namespace Antigen.Statements { diff --git a/Statements/DoWhileStatement.cs b/Antigen/Statements/DoWhileStatement.cs similarity index 98% rename from Statements/DoWhileStatement.cs rename to Antigen/Statements/DoWhileStatement.cs index 8f544f5..f23876d 100644 --- a/Statements/DoWhileStatement.cs +++ b/Antigen/Statements/DoWhileStatement.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/FieldDeclStatement.cs b/Antigen/Statements/FieldDeclStatement.cs similarity index 88% rename from Statements/FieldDeclStatement.cs rename to Antigen/Statements/FieldDeclStatement.cs index cb03f1a..36a4d2c 100644 --- a/Statements/FieldDeclStatement.cs +++ b/Antigen/Statements/FieldDeclStatement.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/ForStatement.cs b/Antigen/Statements/ForStatement.cs similarity index 99% rename from Statements/ForStatement.cs rename to Antigen/Statements/ForStatement.cs index 664dd97..8eeddeb 100644 --- a/Statements/ForStatement.cs +++ b/Antigen/Statements/ForStatement.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/IfElseStatement.cs b/Antigen/Statements/IfElseStatement.cs similarity index 96% rename from Statements/IfElseStatement.cs rename to Antigen/Statements/IfElseStatement.cs index 7bf51eb..da9d38c 100644 --- a/Statements/IfElseStatement.cs +++ b/Antigen/Statements/IfElseStatement.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/LoopStatement.cs b/Antigen/Statements/LoopStatement.cs similarity index 99% rename from Statements/LoopStatement.cs rename to Antigen/Statements/LoopStatement.cs index ea0a153..48d6181 100644 --- a/Statements/LoopStatement.cs +++ b/Antigen/Statements/LoopStatement.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Linq; using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; using Antigen.Tree; using Microsoft.CodeAnalysis; diff --git a/Statements/MethodCallStatement.cs b/Antigen/Statements/MethodCallStatement.cs similarity index 85% rename from Statements/MethodCallStatement.cs rename to Antigen/Statements/MethodCallStatement.cs index b30ebc1..f4c6be3 100644 --- a/Statements/MethodCallStatement.cs +++ b/Antigen/Statements/MethodCallStatement.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/MethodDeclStatement.cs b/Antigen/Statements/MethodDeclStatement.cs similarity index 97% rename from Statements/MethodDeclStatement.cs rename to Antigen/Statements/MethodDeclStatement.cs index db1975e..b49e507 100644 --- a/Statements/MethodDeclStatement.cs +++ b/Antigen/Statements/MethodDeclStatement.cs @@ -2,11 +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; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading.Tasks; namespace Antigen.Statements { diff --git a/Statements/ReturnStatement.cs b/Antigen/Statements/ReturnStatement.cs similarity index 86% rename from Statements/ReturnStatement.cs rename to Antigen/Statements/ReturnStatement.cs index 81b93d8..7e79090 100644 --- a/Statements/ReturnStatement.cs +++ b/Antigen/Statements/ReturnStatement.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/Statement.cs b/Antigen/Statements/Statement.cs similarity index 92% rename from Statements/Statement.cs rename to Antigen/Statements/Statement.cs index ca861a0..eb56067 100644 --- a/Statements/Statement.cs +++ b/Antigen/Statements/Statement.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using Antigen.Tree; +using Antigen.Tree; namespace Antigen.Statements { diff --git a/Statements/StructDeclStatement.cs b/Antigen/Statements/StructDeclStatement.cs similarity index 99% rename from Statements/StructDeclStatement.cs rename to Antigen/Statements/StructDeclStatement.cs index 8a1399e..3426ad3 100644 --- a/Statements/StructDeclStatement.cs +++ b/Antigen/Statements/StructDeclStatement.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; //using Microsoft.CodeAnalysis.CSharp.Syntax; //using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; diff --git a/Statements/SwitchStatement.cs b/Antigen/Statements/SwitchStatement.cs similarity index 97% rename from Statements/SwitchStatement.cs rename to Antigen/Statements/SwitchStatement.cs index 16f52b3..c6b00d6 100644 --- a/Statements/SwitchStatement.cs +++ b/Antigen/Statements/SwitchStatement.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/TryCatchFinallyStatement.cs b/Antigen/Statements/TryCatchFinallyStatement.cs similarity index 97% rename from Statements/TryCatchFinallyStatement.cs rename to Antigen/Statements/TryCatchFinallyStatement.cs index 837a8d6..7d1942c 100644 --- a/Statements/TryCatchFinallyStatement.cs +++ b/Antigen/Statements/TryCatchFinallyStatement.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; namespace Antigen.Statements { diff --git a/Statements/VarDeclStatement.cs b/Antigen/Statements/VarDeclStatement.cs similarity index 88% rename from Statements/VarDeclStatement.cs rename to Antigen/Statements/VarDeclStatement.cs index 63dc3c6..5548358 100644 --- a/Statements/VarDeclStatement.cs +++ b/Antigen/Statements/VarDeclStatement.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Statements/WhileStatement.cs b/Antigen/Statements/WhileStatement.cs similarity index 99% rename from Statements/WhileStatement.cs rename to Antigen/Statements/WhileStatement.cs index 13684b4..a7aae8f 100644 --- a/Statements/WhileStatement.cs +++ b/Antigen/Statements/WhileStatement.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; using Antigen.Expressions; namespace Antigen.Statements diff --git a/Structs.cs b/Antigen/Structs.cs similarity index 62% rename from Structs.cs rename to Antigen/Structs.cs index f0454ee..a27955e 100644 --- a/Structs.cs +++ b/Antigen/Structs.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. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Antigen.Tree; - namespace Antigen { diff --git a/TestCase.cs b/Antigen/TestCase.cs similarity index 94% rename from TestCase.cs rename to Antigen/TestCase.cs index 3b07558..e0b7825 100644 --- a/TestCase.cs +++ b/Antigen/TestCase.cs @@ -1,39 +1,16 @@ using Antigen.Config; -using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Emit; using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Collections.Specialized; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; -using System.Reflection.Metadata; -using System.Runtime.CompilerServices; using System.Text; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -using static System.Net.Mime.MediaTypeNames; +using Utils; namespace Antigen { - public enum TestResult - { - RoslynException, - CompileError, - Overflow, - DivideByZero, - OutputMismatch, - Assertion, - Pass, - OOM - } - public class TestCase { #region Compiler options @@ -90,7 +67,7 @@ public TestCase(int testId, RunOptions runOptions) AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; - s_testRunner = TestRunner.GetInstance(s_runOptions); + s_testRunner = TestRunner.GetInstance(s_runOptions.CoreRun, s_runOptions.OutputDirectory); } public void Generate() diff --git a/TestClass.cs b/Antigen/TestClass.cs similarity index 97% rename from TestClass.cs rename to Antigen/TestClass.cs index 5f55211..7aab963 100644 --- a/TestClass.cs +++ b/Antigen/TestClass.cs @@ -2,19 +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; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen diff --git a/TestMethod.cs b/Antigen/TestMethod.cs similarity index 99% rename from TestMethod.cs rename to Antigen/TestMethod.cs index 384e59f..a649ee1 100644 --- a/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -1,11 +1,9 @@ -using Antigen.Config; -using Antigen.Expressions; +using Antigen.Expressions; using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.VisualBasic.CompilerServices; using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/Tree/AstUtils.cs b/Antigen/Tree/AstUtils.cs similarity index 100% rename from Tree/AstUtils.cs rename to Antigen/Tree/AstUtils.cs diff --git a/Tree/Kinds.cs b/Antigen/Tree/Kinds.cs similarity index 85% rename from Tree/Kinds.cs rename to Antigen/Tree/Kinds.cs index 78f1e49..a7dad71 100644 --- a/Tree/Kinds.cs +++ b/Antigen/Tree/Kinds.cs @@ -2,12 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Antigen.Tree { public enum ExprKind diff --git a/Tree/Node.cs b/Antigen/Tree/Node.cs similarity index 87% rename from Tree/Node.cs rename to Antigen/Tree/Node.cs index 09e8055..76aa4d6 100644 --- a/Tree/Node.cs +++ b/Antigen/Tree/Node.cs @@ -2,12 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Antigen.Tree { public abstract class Node diff --git a/Tree/Operators.cs b/Antigen/Tree/Operators.cs similarity index 100% rename from Tree/Operators.cs rename to Antigen/Tree/Operators.cs diff --git a/Tree/Scope.cs b/Antigen/Tree/Scope.cs similarity index 100% rename from Tree/Scope.cs rename to Antigen/Tree/Scope.cs diff --git a/Tree/Types.cs b/Antigen/Tree/Types.cs similarity index 100% rename from Tree/Types.cs rename to Antigen/Tree/Types.cs diff --git a/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs b/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs index becec74..b907fce 100644 --- a/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/AssignExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs index 095856c..8249043 100644 --- a/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs +++ b/Trimmer/Rewriters/Expressions/BinaryExpRemoval.cs @@ -2,20 +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.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Trimmer.Rewriters.Expressions { - public class BinaryExpRemoval : SyntaxRewriter { private static HashSet s_trimmedExpr = new HashSet(); diff --git a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs index 7d0a7bd..760f695 100644 --- a/Trimmer/Rewriters/Expressions/CastExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/CastExprRemoval.cs @@ -2,13 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; namespace Antigen.Trimmer.Rewriters.Expressions { diff --git a/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs b/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs index e2496ce..07b7677 100644 --- a/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/FieldExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs index 8a5904d..c76c2ea 100644 --- a/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/IdentityNameExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs b/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs index 4b91276..cb640ad 100644 --- a/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/InvocationExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs index fbcbe2e..bb64a92 100644 --- a/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/LiteralExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs index c972212..4f2e646 100644 --- a/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/MemberAccessExprRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs b/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs index 9c9c341..544cca5 100644 --- a/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs +++ b/Trimmer/Rewriters/Expressions/ParenExprRemoval.cs @@ -2,13 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; namespace Antigen.Trimmer.Rewriters.Expressions { diff --git a/Trimmer/Rewriters/Statements/BlockRemoval.cs b/Trimmer/Rewriters/Statements/BlockRemoval.cs index 465742d..ec4afc9 100644 --- a/Trimmer/Rewriters/Statements/BlockRemoval.cs +++ b/Trimmer/Rewriters/Statements/BlockRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; diff --git a/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs index 00edab6..fb415be 100644 --- a/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ConsoleLogStmtRemoval.cs @@ -2,14 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Trimmer.Rewriters.Statements { diff --git a/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs index 89d50f1..dc4be19 100644 --- a/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/DoWhileStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs index 650ff3b..cd45029 100644 --- a/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ExprStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/ForStmtRemoval.cs b/Trimmer/Rewriters/Statements/ForStmtRemoval.cs index 2914c43..69b3cf1 100644 --- a/Trimmer/Rewriters/Statements/ForStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/ForStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs index c5ceee6..2ad49f1 100644 --- a/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/IfElseStmtRemoval.cs @@ -2,11 +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.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Antigen.Trimmer.Rewriters diff --git a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs index 9208184..447339a 100644 --- a/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/LocalDeclStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs index 023b491..0143921 100644 --- a/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/MethodDeclStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs b/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs index 050c4c1..0d6a713 100644 --- a/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/StructDeclStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs b/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs index e15f39a..3a7a731 100644 --- a/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/SwitchStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/SyntaxRewriter.cs b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs index ece2025..b9dcd76 100644 --- a/Trimmer/Rewriters/Statements/SyntaxRewriter.cs +++ b/Trimmer/Rewriters/Statements/SyntaxRewriter.cs @@ -2,13 +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; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Antigen.Trimmer.Rewriters { diff --git a/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs b/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs index 24684f0..0a4daab 100644 --- a/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/TryCatchFinallyStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs b/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs index b2cae3f..11de4ac 100644 --- a/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs +++ b/Trimmer/Rewriters/Statements/WhileStmtRemoval.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index d25ce72..000658d 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -2,42 +2,56 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Antigen; +using Antigen.Trimmer.Rewriters; +using Antigen.Trimmer.Rewriters.Expressions; +using Antigen.Trimmer.Rewriters.Statements; +using CommandLine; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Antigen.Config; -using Antigen.Trimmer.Rewriters; -using Antigen.Trimmer.Rewriters.Expressions; -using Antigen.Trimmer.Rewriters.Statements; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Utils; -namespace Antigen.Trimmer +namespace Trimmer { public class TestTrimmer { - RunOptions _runOptions; private string _testFileToTrim; + private string _outputFolder; private static TestRunner _testRunner; private Dictionary _baselineVariables; private Dictionary _testVariables; private string _originalTestAssertion; static int s_iterId = 1; - public TestTrimmer(string testFileToTrim, RunOptions runOptions) + static int Main(string[] args) + { + return Parser.Default.ParseArguments(args).MapResult(Run, err => 1); + } + + private static int Run(CommandLineOptions opts) + { + string testCaseToTrim = opts.ReproFile; + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, opts); + testTrimmer.Trim(); + return 0; + } + + public TestTrimmer(string testFileToTrim, CommandLineOptions opts) { if (!File.Exists(testFileToTrim)) { throw new Exception($"{testFileToTrim} doesn't exist."); } - _runOptions = runOptions; _testFileToTrim = testFileToTrim; - _testRunner = TestRunner.GetInstance(_runOptions); + _outputFolder = opts.IssuesFolder; + _testRunner = TestRunner.GetInstance(opts.CoreRunPath, opts.IssuesFolder); ParseEnvironment(); } @@ -181,10 +195,10 @@ public bool TrimExpressions() public bool TrimEnvVars() { bool trimmedAtleastOne = false; - SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText( _testFileToTrim)).GetRoot(); + SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); var keys = _testVariables.Keys.ToList(); - foreach(var envVar in keys) + foreach (var envVar in keys) { if (envVar.Contains("AltJit")) { @@ -309,7 +323,8 @@ private bool Trim(List trimmerList) try { treeAfterTrim = trimmer.Visit(recentTree); - } catch (ArgumentNullException) + } + catch (ArgumentNullException) { gotException = true; } @@ -375,13 +390,8 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< { return TestResult.CompileError; } - //else - //{ - // string workingFile = Path.Combine(RunOptions.OutputDirectory, $"{Name}-working.g.cs"); - // File.WriteAllText(workingFile, testCaseRoot.ToFullString()); - //} - string currRunBaselineOutput = hasAssertion ? string.Empty :_testRunner.Execute(compileResult, EnvVarOptions.BaseLineVars(), 10); + string currRunBaselineOutput = hasAssertion ? string.Empty : _testRunner.Execute(compileResult, null, 10); string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 40); TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; @@ -467,8 +477,23 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< File.WriteAllText(failFile, fileContents.ToString()); _testFileToTrim = failFile; - File.Move(compileResult.AssemblyFullPath, Path.Combine(_runOptions.OutputDirectory, $"{failedFileName}.exe"), overwrite: true); + File.Move(compileResult.AssemblyFullPath, Path.Combine(_outputFolder, $"{failedFileName}.exe"), overwrite: true); return verificationResult; - } + } + } + + public class CommandLineOptions + { + [Option(shortName: 'c', longName: "CoreRun", Required = true, HelpText = "Path to CoreRun/CoreRun.exe.")] + public string CoreRunPath { get; set; } + + [Option(shortName: 'f', longName: "ReproFile", Required = true, HelpText = "Full path of the repro file.")] + public string ReproFile { get; set; } + + [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where trimmed issue will be copied.")] + public string IssuesFolder { get; set; } + + [Option(shortName: 'j', longName: "AltJitName", Required = false, HelpText = "Name of altjit. By default, current OS/arch.")] + public string AltJitName { get; set; } } } diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj new file mode 100644 index 0000000..adbb286 --- /dev/null +++ b/Trimmer/Trimmer.csproj @@ -0,0 +1,18 @@ + + + + Exe + net5.0 + + + + + + + + + + + + + diff --git a/Helpers/RslnUtilities.cs b/Utils/RslnUtilities.cs similarity index 97% rename from Helpers/RslnUtilities.cs rename to Utils/RslnUtilities.cs index 4ac85f8..b297a9f 100644 --- a/Helpers/RslnUtilities.cs +++ b/Utils/RslnUtilities.cs @@ -2,18 +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; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Antigen +namespace Utils { public class RslnUtilities { diff --git a/Helpers/TestRunner.cs b/Utils/TestRunner.cs similarity index 80% rename from Helpers/TestRunner.cs rename to Utils/TestRunner.cs index bcdbedf..af1dc0b 100644 --- a/Helpers/TestRunner.cs +++ b/Utils/TestRunner.cs @@ -4,24 +4,37 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; -using Antigen.Config; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; -namespace Antigen +namespace Utils { + public enum TestResult + { + RoslynException, + CompileError, + Overflow, + DivideByZero, + OutputMismatch, + Assertion, + Pass, + OOM + } + public class TestRunner { + internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); + private static TestRunner _testRunner; private static readonly bool s_useDotnet = false; - private RunOptions RunOptions; + private readonly string _coreRun; + private readonly string _outputDirectory; private static readonly string s_corelibPath = typeof(object).Assembly.Location; private static readonly MetadataReference[] s_references = @@ -33,16 +46,17 @@ public class TestRunner MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location), }; - private TestRunner(RunOptions runOptions) + private TestRunner(string coreRun, string outputFolder) { - RunOptions = runOptions; + _coreRun = coreRun; + _outputDirectory = outputFolder; } - public static TestRunner GetInstance(RunOptions runOptions) + public static TestRunner GetInstance(string coreRun, string outputFolder) { if (_testRunner == null) { - _testRunner = new TestRunner(runOptions); + _testRunner = new TestRunner(coreRun, outputFolder); } return _testRunner; } @@ -53,9 +67,9 @@ public static TestRunner GetInstance(RunOptions runOptions) /// internal CompileResult Compile(SyntaxTree programTree, string assemblyName) { - string assemblyFullPath = Path.Combine(RunOptions.OutputDirectory, $"{assemblyName}.exe"); + string assemblyFullPath = Path.Combine(_outputDirectory, $"{assemblyName}.exe"); - var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, EnvVarOptions.CompileOptions); + var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, CompileOptions); using (var ms = new MemoryStream()) { @@ -97,9 +111,12 @@ internal string Execute(CompileResult compileResult, Dictionary if (s_useDotnet) { - foreach (var envVar in environmentVariables) + if (environmentVariables != null) { - Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); + foreach (var envVar in environmentVariables) + { + Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); + } } //TODO: if execute in debug vs. release dotnet.exe @@ -130,9 +147,12 @@ internal string Execute(CompileResult compileResult, Dictionary sw.Close(); } - foreach (var envVar in environmentVariables) + if (environmentVariables != null) { - Environment.SetEnvironmentVariable(envVar.Key, null, EnvironmentVariableTarget.Process); + foreach (var envVar in environmentVariables) + { + Environment.SetEnvironmentVariable(envVar.Key, null, EnvironmentVariableTarget.Process); + } } return Encoding.UTF8.GetString(ms.ToArray()); @@ -141,7 +161,7 @@ internal string Execute(CompileResult compileResult, Dictionary { ProcessStartInfo info = new ProcessStartInfo { - FileName = RunOptions.CoreRun, + FileName = _coreRun, Arguments = compileResult.AssemblyFullPath, WorkingDirectory = Environment.CurrentDirectory, RedirectStandardOutput = true, @@ -149,9 +169,12 @@ internal string Execute(CompileResult compileResult, Dictionary UseShellExecute = false, }; - foreach (var envVar in environmentVariables) + if (environmentVariables != null) { - info.EnvironmentVariables[envVar.Key] = envVar.Value; + foreach (var envVar in environmentVariables) + { + info.EnvironmentVariables[envVar.Key] = envVar.Value; + } } using (Process proc = new Process()) From 4261ab17c4c9874cb8f8faa2116451b6aef85950 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 23 Sep 2021 23:16:49 -0700 Subject: [PATCH 081/149] Fix the Microsoft.Codeanalysis --- Antigen/TestMethod.cs | 3 ++- Antigen/Tree/Types.cs | 5 ++--- Trimmer/Trimmer.csproj | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index a649ee1..3bda05c 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -501,7 +501,8 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) List>> catchClauses = new (); - var allExceptions = Tree.ValueType.AllExceptions.Select(x => x.Key).ToList(); + // Clone + var allExceptions = Tree.ValueType.AllExceptions.Select(x => x).ToList(); var caughtExceptions = new List(); for (int catchId = 0; catchId < catchCounts; catchId++) diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index 938f2e2..bfa8057 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -239,11 +239,10 @@ public string VariableNameHint() return _variableNameHint; } - public static IDictionary AllExceptions => + public static IReadOnlyList AllExceptions => typeof(Exception).Assembly.GetTypes() .Where(x => x.IsSubclassOf(typeof(Exception))) - .Where(n => n.FullName.StartsWith("System.") && n.FullName.LastIndexOf(".") == 6) - .ToDictionary(t => t, t => CatchDeclaration(IdentifierName(t.Name))); + .Where(n => n.FullName.StartsWith("System.") && n.FullName.LastIndexOf(".") == 6).ToList(); public override string ToString() { diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index adbb286..8851ee1 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -7,7 +7,7 @@ - + From 716449fbdc85feca8e929bab3463a879ca1c90e5 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 09:12:50 -0700 Subject: [PATCH 082/149] Fix number of iterations/duration logic --- Antigen/Antigen.cs | 20 +++++++++++++++----- Antigen/Config/antigen.json | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 10c2d76..58d55d4 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -40,14 +40,22 @@ private static int Run(CommandLineOptions opts) PRNG.Initialize(s_runOptions.Seed); s_runOptions.CoreRun = opts.CoreRunPath; s_runOptions.OutputDirectory = opts.IssuesFolder; + if (opts.RunDuration > 0) + { + s_runOptions.RunDuration = opts.RunDuration; + } if (opts.NumTestCases > 0) { s_runOptions.NumTestCases = opts.NumTestCases; } - if (opts.RunDuration > 0) + if (s_runOptions.RunDuration != -1) { - s_runOptions.RunDuration = opts.RunDuration; + Console.WriteLine($"Starting Antigen for {s_runOptions.RunDuration} minutes."); + } + else + { + Console.WriteLine($"Starting Antigen for {s_runOptions.NumTestCases} iterations."); } if (!File.Exists(s_runOptions.CoreRun)) @@ -96,11 +104,13 @@ private static bool Done { get { - if ((DateTime.Now - s_startTime).Minutes >= s_runOptions.RunDuration) + // If RunDuration was specified, use that. + if (s_runOptions.RunDuration != -1) { - return true; + return (DateTime.Now - s_startTime).Minutes >= s_runOptions.RunDuration; } - if (s_testId >= s_runOptions.NumTestCases) + // Otherwise use number of test cases. + else if (s_testId >= s_runOptions.NumTestCases) { return true; } diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 83245f4..4b0654b 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -2,7 +2,7 @@ "Seed": -1, "OutputDirectory": ".", "NumTestCases": 1000, - "RunDuration": 2147483647, + "RunDuration": -1, "BaselineEnvVars": [ { "Name": "Default", From f1cfbaf8195d289e884ffd028bd45ebd9bb1c013 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 09:30:19 -0700 Subject: [PATCH 083/149] Fix test stats summary --- Antigen/Antigen.cs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 58d55d4..99c2fdf 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -6,12 +6,14 @@ using Antigen.Config; using CommandLine; using Utils; +using System.Linq; namespace Antigen { class Program { - static readonly object s_spinLock = new object(); + private static readonly object s_spinLock = new object(); + private static int totalTestCount = 0; private static readonly RunOptions s_runOptions = RunOptions.Initialize(); private static readonly Dictionary s_stats = new() { @@ -123,23 +125,21 @@ private static bool Done /// Save the result. /// /// - private static void SaveResult(Dictionary localStats) + private static void SaveResult(Dictionary localStats, int localTestCount) { lock (s_spinLock) { + totalTestCount += localTestCount; foreach (var resultStat in localStats) { s_stats[resultStat.Key] += resultStat.Value; + localStats[resultStat.Key] = 0; } - if ((s_stats.Count % 50) == 0) + if ((totalTestCount % 100) == 0) { - Console.Write("** "); - foreach (var st in s_stats) - { - Console.Write($"{Enum.GetName(typeof(TestResult), st.Key)}={st.Value}, "); - } - Console.WriteLine(); + var nonZeroStats = s_stats.Where(stat => stat.Value > 0); + Console.WriteLine($"*** {string.Join(", ", nonZeroStats.Select(stat => $"{Enum.GetName(typeof(TestResult), stat.Key)}={stat.Value}"))}"); } } } @@ -158,6 +158,7 @@ static void RunTest() { TestResult.OOM, 0 }, }; + int testCount = 0; while (!Done) { var currTestId = GetNextTestId(); @@ -171,12 +172,12 @@ static void RunTest() (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, (DateTime.Now - s_startTime).ToString()); - + testCount++; localStats[result]++; - if (localStats.Count == 10) + if (testCount == 50) { - SaveResult(localStats); - localStats.Clear(); + SaveResult(localStats, testCount); + testCount = 0; } GC.Collect(); From 94725442433ebc35d144e82f80fef48992adaee4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 09:32:40 -0700 Subject: [PATCH 084/149] Print stats at the end of run --- Antigen/Antigen.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 99c2fdf..3640532 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -7,6 +7,7 @@ using CommandLine; using Utils; using System.Linq; +using System.Runtime.CompilerServices; namespace Antigen { @@ -72,7 +73,7 @@ private static int Run(CommandLineOptions opts) Parallel.For(0, 2, (p) => RunTest()); Console.WriteLine($"Executed {s_testId} test cases."); - + DisplayStats(); } catch (OutOfMemoryException oom) { @@ -138,12 +139,18 @@ private static void SaveResult(Dictionary localStats, int local if ((totalTestCount % 100) == 0) { - var nonZeroStats = s_stats.Where(stat => stat.Value > 0); - Console.WriteLine($"*** {string.Join(", ", nonZeroStats.Select(stat => $"{Enum.GetName(typeof(TestResult), stat.Key)}={stat.Value}"))}"); + DisplayStats(); } } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void DisplayStats() + { + var nonZeroStats = s_stats.Where(stat => stat.Value > 0); + Console.WriteLine($"*** {string.Join(", ", nonZeroStats.Select(stat => $"{Enum.GetName(typeof(TestResult), stat.Key)}={stat.Value}"))}"); + } + static void RunTest() { Dictionary localStats = new Dictionary() From 043f4bd990d2c56bdc5f7f229f5d17359bb6c470 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 10:28:20 -0700 Subject: [PATCH 085/149] Minor change --- Antigen/TestCase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index e0b7825..7143762 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -191,10 +191,9 @@ private TestResult TheTestResult(string assemblyPath, TestResult result) { File.Delete(assemblyPath); } - catch (Exception ex) + catch { // ignore errors - Console.WriteLine($"Error deleting {assemblyPath} : {ex}"); } return result; } From 93ac54342d119434b0c7d984cff3c4e777e1bc46 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 11:14:49 -0700 Subject: [PATCH 086/149] Update to net6.0 --- Antigen/Antigen.csproj | 2 +- Trimmer/Trimmer.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index e513e24..6e2b594 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index 8851ee1..df5ffb2 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 From d2cccd41a6ac4b66a02b9778311e3aa0843c9e14 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 12:53:52 -0700 Subject: [PATCH 087/149] Revert "Update to net6.0" This reverts commit 93ac54342d119434b0c7d984cff3c4e777e1bc46. --- Antigen/Antigen.csproj | 2 +- Trimmer/Trimmer.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index 6e2b594..e513e24 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net5.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index df5ffb2..8851ee1 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net5.0 From 50113e11418d6fdadc8a46935e51e26a64deb68b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Sep 2021 23:14:46 -0700 Subject: [PATCH 088/149] Fix some DivideByZero exceptions --- Antigen/Config/RunOptions.cs | 4 +-- Antigen/Config/antigen.json | 2 +- Antigen/Expressions/BinaryExpression.cs | 24 ++------------ Antigen/Helpers/Helper.cs | 42 +++++++++++++++++++++++++ Antigen/Statements/AssignStatement.cs | 5 +-- Antigen/TestCase.cs | 3 +- Antigen/TestMethod.cs | 9 +++--- 7 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 Antigen/Helpers/Helper.cs diff --git a/Antigen/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs index 32fb559..eb145d4 100644 --- a/Antigen/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -16,10 +16,10 @@ public class RunOptions public string OutputDirectory = "." + Path.DirectorySeparatorChar; // Total number of test cases (overrides number specified in each XML config file) - public long NumTestCases = 0; + public long NumTestCases; // Duration to execute tests for (overrides number specified in each XML config file) - public int RunDuration = 0; + public int RunDuration; [NonSerialized()] public string CoreRun = null; diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 4b0654b..0ba662d 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -1,7 +1,7 @@ { "Seed": -1, "OutputDirectory": ".", - "NumTestCases": 1000, + "NumTestCases": -1, "RunDuration": -1, "BaselineEnvVars": [ { diff --git a/Antigen/Expressions/BinaryExpression.cs b/Antigen/Expressions/BinaryExpression.cs index 5213ccf..8ae5667 100644 --- a/Antigen/Expressions/BinaryExpression.cs +++ b/Antigen/Expressions/BinaryExpression.cs @@ -13,31 +13,11 @@ public class BinaryExpression : Expression public readonly Operator Op; public readonly Expression Right; - public BinaryExpression(TestCase testCase, Tree.ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase) + public BinaryExpression(TestCase testCase, ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase) { Left = lhs; Op = op; - - if ( - (Op.Oper == SyntaxKind.DivideAssignmentExpression) || - (Op.Oper == SyntaxKind.DivideExpression) || - (Op.Oper == SyntaxKind.ModuloAssignmentExpression) || - (Op.Oper == SyntaxKind.ModuloExpression)) - { - // To avoid divide by zero errors - var addExpression = new AssignExpression( - testCase, - leftType, - new ParenthsizedExpression(testCase, rhs), - Operator.ForSyntaxKind(SyntaxKind.AddExpression), - ConstantValue.GetRandomConstantInt(10, 100)); - - Right = new CastExpression(testCase, addExpression, leftType); - } - else - { - Right = rhs; - } + Right = Helper.FixDivideByZero(testCase, leftType, op, rhs); } public override string ToString() diff --git a/Antigen/Helpers/Helper.cs b/Antigen/Helpers/Helper.cs new file mode 100644 index 0000000..e985d00 --- /dev/null +++ b/Antigen/Helpers/Helper.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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Expressions; +using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; + +namespace Antigen +{ + public class Helper + { + public static Expression FixDivideByZero(TestCase testCase, Tree.ValueType leftType, Operator op, Expression rhs) + { + if ( + (op.Oper == SyntaxKind.DivideAssignmentExpression) || + (op.Oper == SyntaxKind.DivideExpression) || + (op.Oper == SyntaxKind.ModuloAssignmentExpression) || + (op.Oper == SyntaxKind.ModuloExpression)) + { + // To avoid divide by zero errors + var addExpression = new AssignExpression( + testCase, + leftType, + new ParenthsizedExpression(testCase, rhs), + Operator.ForSyntaxKind(SyntaxKind.AddExpression), + ConstantValue.GetRandomConstantInt(1, 100)); + + return new CastExpression(testCase, addExpression, leftType); + } + else + { + return rhs; + } + } + } +} diff --git a/Antigen/Statements/AssignStatement.cs b/Antigen/Statements/AssignStatement.cs index 83fa606..5003fc8 100644 --- a/Antigen/Statements/AssignStatement.cs +++ b/Antigen/Statements/AssignStatement.cs @@ -4,6 +4,7 @@ using Antigen.Expressions; using Antigen.Tree; +using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Statements { @@ -13,11 +14,11 @@ public class AssignStatement : Statement public readonly Operator Op; public readonly Expression Right; - public AssignStatement(TestCase testCase, Expression lhs, Operator op, Expression rhs) : base(testCase) + public AssignStatement(TestCase testCase, ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase) { Left = lhs; Op = op; - Right = rhs; + Right = Helper.FixDivideByZero(testCase, leftType, op, rhs); } public override string ToString() diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 7143762..a3f0604 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -143,8 +143,7 @@ public TestResult Verify() { if (test.Contains(knownError)) { - return TheTestResult(compileResult.AssemblyFullPath, test.StartsWith("System.OverflowException:") ? - TestResult.Overflow : TestResult.DivideByZero); + return TheTestResult(compileResult.AssemblyFullPath, test.Contains("System.OverflowException:") ? TestResult.Overflow : TestResult.DivideByZero); } } } diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 3bda05c..0427532 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -169,10 +169,11 @@ public virtual MethodDeclStatement Generate() //TODO-future: Select any assignOper //Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); - var lhs = ExprHelper(ExprKind.VariableExpression, nonLeafMethod.Data.ReturnType, 0); + Tree.ValueType lhsType = nonLeafMethod.Data.ReturnType; + var lhs = ExprHelper(ExprKind.VariableExpression, lhsType, 0); var rhs = MethodCallHelper(nonLeafMethod.Data, 0); - methodBody.Add(new AssignStatement(TC, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs)); + methodBody.Add(new AssignStatement(TC, lhsType, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs)); } } @@ -342,7 +343,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); Expression rhs = ExprHelper(rhsKind, rhsExprType, 0); - return new AssignStatement(TC, lhs, assignOper, rhs); + return new AssignStatement(TC, lhsExprType, lhs, assignOper, rhs); } case StmtKind.ForStatement: { @@ -792,7 +793,7 @@ public Statement VariableAssignmentHelper(Tree.ValueType exprType, string variab } while (noOfAttempts++ < 5); Debug.Assert(lhs.ToString() != rhs.ToString()); - return new AssignStatement(TC, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs); + return new AssignStatement(TC, exprType, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs); } /// From 9129c75e67fcc173dd205f5b8e79c6cef673cc72 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 00:07:28 -0700 Subject: [PATCH 089/149] Remove unnecessary using --- Antigen/Config/EnvVarOptions.cs | 2 - Antigen/Expressions/BinaryExpression.cs | 1 - Antigen/Helpers/Helper.cs | 5 -- Antigen/Statements/AssignStatement.cs | 1 - Antigen/Statements/StructDeclStatement.cs | 60 ----------------------- Antigen/TestCase.cs | 1 - Antigen/TestMethod.cs | 1 - Antigen/Tree/Types.cs | 2 - Trimmer/TestTrimmer.cs | 1 - 9 files changed, 74 deletions(-) diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index febd46b..90a04c1 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -4,8 +4,6 @@ using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Config { diff --git a/Antigen/Expressions/BinaryExpression.cs b/Antigen/Expressions/BinaryExpression.cs index 8ae5667..4bc5af5 100644 --- a/Antigen/Expressions/BinaryExpression.cs +++ b/Antigen/Expressions/BinaryExpression.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Antigen.Tree; -using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Expressions { diff --git a/Antigen/Helpers/Helper.cs b/Antigen/Helpers/Helper.cs index e985d00..8248883 100644 --- a/Antigen/Helpers/Helper.cs +++ b/Antigen/Helpers/Helper.cs @@ -2,11 +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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Antigen.Expressions; using Antigen.Tree; using Microsoft.CodeAnalysis.CSharp; diff --git a/Antigen/Statements/AssignStatement.cs b/Antigen/Statements/AssignStatement.cs index 5003fc8..7de9a33 100644 --- a/Antigen/Statements/AssignStatement.cs +++ b/Antigen/Statements/AssignStatement.cs @@ -4,7 +4,6 @@ using Antigen.Expressions; using Antigen.Tree; -using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Statements { diff --git a/Antigen/Statements/StructDeclStatement.cs b/Antigen/Statements/StructDeclStatement.cs index 3426ad3..200598d 100644 --- a/Antigen/Statements/StructDeclStatement.cs +++ b/Antigen/Statements/StructDeclStatement.cs @@ -37,66 +37,6 @@ public override string ToString() return strBuilder.ToString(); } - - ///// - ///// Generate structs in this class - ///// - ///// - //private static List GenerateStructs() - //{ - // List structs = new List(); - - // for (int structIndex = 1; structIndex <= TC.Config.StructCount; structIndex++) - // { - // string structName = $"S{structIndex}"; - // var (structDecl, fields) = GenerateStruct(structName, structName, structIndex, 1); - // structs.Add(structDecl); - // CurrentScope.AddStructType(structName, fields); - // } - - // (MemberDeclarationSyntax, List) GenerateStruct(string structName, string structType, int structIndex, int depth) - // { - // StructDeclarationSyntax structDeclaration = StructDeclaration(structName) - // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); - - // List fieldsTree = new List(); - // List fieldsMetadata = new List(); - // int fieldCount = PRNG.Next(1, TC.Config.StructFieldCount); - // for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++) - // { - // if (PRNG.Decide(TC.Config.NestedStructProbability) && depth < TC.Config.NestedStructDepth) - // { - // string nestedStructName = $"S{structIndex}_D{depth}_F{fieldIndex}"; - // string nestedStructType = structType + "." + nestedStructName; - // var (structDecl, childFields) = GenerateStruct(nestedStructName, nestedStructType, structIndex, depth + 1); - // fieldsTree.Add(structDecl); - // CurrentScope.AddStructType(nestedStructType, childFields); - // structName = nestedStructName; - // continue; - // } - - // Tree.ValueType fieldType; - // string fieldName; - - // if (PRNG.Decide(TC.Config.StructFieldTypeProbability) && CurrentScope.NumOfStructTypes > 0) - // { - // fieldType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; - // } - // else - // { - // fieldType = GetASTUtils().GetRandomExprType(); - // } - - // fieldName = Helpers.GetVariableName(fieldType, fieldIndex); - // fieldsTree.Add(FieldDeclaration(Helpers.GetVariableDeclaration(fieldType, fieldName)).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))); - // fieldsMetadata.Add(new StructField(fieldType, fieldName)); - // } - - // return (structDeclaration.WithMembers(fieldsTree.ToSyntaxList()), fieldsMetadata); - // } - - // return structs; - //} } /// diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index a3f0604..0b526c8 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -2,7 +2,6 @@ using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 0427532..28b627e 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.Linq; using System.Text; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen { diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index bfa8057..455dfbc 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -1,11 +1,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Antigen.Tree { diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 000658d..187798f 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.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 Antigen; using Antigen.Trimmer.Rewriters; using Antigen.Trimmer.Rewriters.Expressions; using Antigen.Trimmer.Rewriters.Statements; From 17c08f253a2017bb79cd09e998d1e40962bb13da Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 00:08:04 -0700 Subject: [PATCH 090/149] Use universal variableId --- Antigen/TestClass.cs | 14 ++++++++++---- Antigen/TestMethod.cs | 11 +++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Antigen/TestClass.cs b/Antigen/TestClass.cs index 7aab963..821fa0b 100644 --- a/Antigen/TestClass.cs +++ b/Antigen/TestClass.cs @@ -22,6 +22,12 @@ public class TestClass public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } private List> _methods { get; set; } + private int _variableId; + + public string GetVariableName(Tree.ValueType variableType) + { + return variableType.VariableNameHint() + "_" + _variableId++; + } public AstUtils GetASTUtils() { @@ -35,6 +41,7 @@ public TestClass(TestCase tc, string className) ClassName = className; TC = tc; _methods = new List>(); + _variableId = 0; } public void RegisterMethod(MethodSignature methodSignature) @@ -179,7 +186,7 @@ StructDeclStatement GenerateStruct(string structName, string structType, int str fieldType = GetASTUtils().GetRandomExprType(); } - fieldName = Helpers.GetVariableName(fieldType, fieldIndex); + fieldName = GetVariableName(fieldType); //fieldsTree.Add(new VarDeclStatement(TC, fieldType, fieldName, null)); fieldsMetadata.Add(new StructField(fieldType, fieldName)); } @@ -236,10 +243,9 @@ private List GenerateFields(bool isStatic) List fields = new List(); // TODO-TEMP initialize one variable of each type - int _variablesCount = 0; foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { - string variableName = (isStatic ? "s_" : string.Empty) + Helpers.GetVariableName(variableType, _variablesCount++); + string variableName = (isStatic ? "s_" : string.Empty) + GetVariableName(variableType); Expression rhs = ConstantValue.GetConstantValue(variableType, TC._numerals); @@ -251,7 +257,7 @@ private List GenerateFields(bool isStatic) // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { - string variableName = (isStatic ? "s_" : string.Empty) + Helpers.GetVariableName(structType, _variablesCount++); + string variableName = (isStatic ? "s_" : string.Empty) + GetVariableName(structType); Expression rhs = new CreationExpression(TC, structType.TypeName, null); CurrentScope.AddLocal(structType, variableName); diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 28b627e..f51c658 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -28,7 +28,6 @@ public class TestMethod private readonly Dictionary _statementsCount = new(); #endif - private int _variablesCount = 0; private int _loopVarCount = 0; internal HashSet callsFromThisMethod = new HashSet(); @@ -103,7 +102,7 @@ public virtual MethodDeclStatement Generate() // TODO-TEMP initialize one variable of each type foreach (var variableType in Tree.ValueType.GetTypes()) { - var variableName = Helpers.GetVariableName(variableType, _variablesCount++); + var variableName = _testClass.GetVariableName(variableType); var rhs = ExprHelper(ExprKind.LiteralExpression, variableType, 0); CurrentScope.AddLocal(variableType, variableName); @@ -114,7 +113,7 @@ public virtual MethodDeclStatement Generate() // TODO-TEMP initialize one variable of each struct type foreach (var structType in CurrentScope.AllStructTypes) { - var variableName = Helpers.GetVariableName(structType, _variablesCount++); + var variableName = _testClass.GetVariableName(structType); CurrentScope.AddLocal(structType, variableName); @@ -132,7 +131,7 @@ public virtual MethodDeclStatement Generate() continue; } - var aliasVariableName = Helpers.GetVariableName(structType, _variablesCount++); + var aliasVariableName = _testClass.GetVariableName(structType); CurrentScope.AddLocal(structType, aliasVariableName); @@ -209,7 +208,7 @@ protected virtual void PopulateMethodSignature() { var paramType = GetRandomExprType(); var passingWay = PRNG.WeightedChoice(_valuePassing); - string paramName = "p_" + Helpers.GetVariableName(paramType, paramIndex); + string paramName = "p_" + _testClass.GetVariableName(paramType); // Add parameters to the scope except the one that is marked as OUT // OUT parameters will be added once they are initialized. @@ -245,7 +244,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) { Tree.ValueType variableType = GetRandomExprType(); - string variableName = Helpers.GetVariableName(variableType, _variablesCount++); + string variableName = _testClass.GetVariableName(variableType); Expression rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); From dda8d0b36412362f7ba6c7d063c3d116d2854500 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 09:41:56 -0700 Subject: [PATCH 091/149] Log the Done condition --- Antigen/Antigen.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 3640532..4df3395 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -107,10 +107,13 @@ private static bool Done { get { + var now = DateTime.Now; + var diff = (now - s_startTime); + Console.WriteLine($"----- start: {s_startTime}, now: {now}, diff: {diff}, minutes: {diff.Minutes}, duration: {s_runOptions.RunDuration}, s_testId: {s_testId}, numTestCases: {s_runOptions.NumTestCases}"); // If RunDuration was specified, use that. if (s_runOptions.RunDuration != -1) { - return (DateTime.Now - s_startTime).Minutes >= s_runOptions.RunDuration; + return diff.Minutes >= s_runOptions.RunDuration; } // Otherwise use number of test cases. else if (s_testId >= s_runOptions.NumTestCases) @@ -194,10 +197,10 @@ static void RunTest() public class CommandLineOptions { - [Option(shortName: 'c', longName: "CoreRun", Required = true, HelpText = "Path to CoreRun/CoreRun.exe.")] + [Option(shortName: 'c', longName: "CoreRun", Required = true, HelpText = "Full path to CoreRun/CoreRun.exe.")] public string CoreRunPath { get; set; } - [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where issues will be copied.")] + [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Full path to folder where issues will be copied.")] public string IssuesFolder { get; set; } [Option(shortName: 'n', longName: "NumTestCases", Required = false, HelpText = "Number of test cases to execute. By default, 1000.")] From 1bf3b0d8a134f21521566db19b4c3b696d0c49e0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 09:43:44 -0700 Subject: [PATCH 092/149] Delete Antigen/Helpers/VariableDeclarationHelper.cs --- Antigen/Helpers/VariableDeclarationHelper.cs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 Antigen/Helpers/VariableDeclarationHelper.cs diff --git a/Antigen/Helpers/VariableDeclarationHelper.cs b/Antigen/Helpers/VariableDeclarationHelper.cs deleted file mode 100644 index 1fe58a7..0000000 --- a/Antigen/Helpers/VariableDeclarationHelper.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Antigen -{ - public static partial class Helpers - { - public static string GetVariableName(Tree.ValueType variableType, int id) - { - return variableType.VariableNameHint() + "_" + id; - } - } -} From b5d9876014cda7ad4fabe44047b04cf21180148b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 22:29:02 -0700 Subject: [PATCH 093/149] Fix the TotalMinutes --- Antigen/Antigen.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 4df3395..2b79a5b 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -107,13 +107,10 @@ private static bool Done { get { - var now = DateTime.Now; - var diff = (now - s_startTime); - Console.WriteLine($"----- start: {s_startTime}, now: {now}, diff: {diff}, minutes: {diff.Minutes}, duration: {s_runOptions.RunDuration}, s_testId: {s_testId}, numTestCases: {s_runOptions.NumTestCases}"); // If RunDuration was specified, use that. if (s_runOptions.RunDuration != -1) { - return diff.Minutes >= s_runOptions.RunDuration; + return (DateTime.Now - s_startTime).TotalMinutes >= s_runOptions.RunDuration; } // Otherwise use number of test cases. else if (s_testId >= s_runOptions.NumTestCases) From 2eb1c994f0322c45ec1b8c1f264e40107768d0a9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 25 Sep 2021 22:30:07 -0700 Subject: [PATCH 094/149] Misc. changes --- Antigen/Helpers/PreGenerated.cs | 3 -- Antigen/Statements/StructDeclStatement.cs | 3 -- Antigen/TestMethod.cs | 58 +++++++++++------------ 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/Antigen/Helpers/PreGenerated.cs b/Antigen/Helpers/PreGenerated.cs index ef0b9d3..ff45583 100644 --- a/Antigen/Helpers/PreGenerated.cs +++ b/Antigen/Helpers/PreGenerated.cs @@ -3,9 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Text; -//using Microsoft.CodeAnalysis.CSharp.Syntax; -//using Microsoft.CodeAnalysis.CSharp; -//using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using Antigen.Statements; namespace Antigen diff --git a/Antigen/Statements/StructDeclStatement.cs b/Antigen/Statements/StructDeclStatement.cs index 200598d..c67b28a 100644 --- a/Antigen/Statements/StructDeclStatement.cs +++ b/Antigen/Statements/StructDeclStatement.cs @@ -5,9 +5,6 @@ using System; using System.Collections.Generic; using System.Text; -//using Microsoft.CodeAnalysis.CSharp.Syntax; -//using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - namespace Antigen.Statements { diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index f51c658..3470287 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -913,35 +913,35 @@ private Tree.ValueType GetRandomExprType() } } - private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) - { -#if DEBUG - string typeName = expression.GetType().Name; - if (!_expressionsCount.ContainsKey(typeName)) - { - _expressionsCount[typeName] = 0; - } - _expressionsCount[typeName]++; - return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{_expressionsCount[typeName]}: {comment} */"))); -#else - return expression; -#endif - } - - private StatementSyntax Annotate(StatementSyntax statement, string comment, int depth) - { -#if DEBUG - string typeName = statement.GetType().Name; - if (!_statementsCount.ContainsKey(typeName)) - { - _statementsCount[typeName] = 0; - } - _statementsCount[typeName]++; - return statement.WithTrailingTrivia(TriviaList(Comment($"/* {depth}: S#{_statementsCount[typeName]}: {comment} */"))); -#else - return statement; -#endif - } +// private ExpressionSyntax Annotate(ExpressionSyntax expression, string comment) +// { +//#if DEBUG +// string typeName = expression.GetType().Name; +// if (!_expressionsCount.ContainsKey(typeName)) +// { +// _expressionsCount[typeName] = 0; +// } +// _expressionsCount[typeName]++; +// return expression.WithTrailingTrivia(TriviaList(Comment($"/* E#{_expressionsCount[typeName]}: {comment} */"))); +//#else +// return expression; +//#endif +// } + +// private StatementSyntax Annotate(StatementSyntax statement, string comment, int depth) +// { +//#if DEBUG +// string typeName = statement.GetType().Name; +// if (!_statementsCount.ContainsKey(typeName)) +// { +// _statementsCount[typeName] = 0; +// } +// _statementsCount[typeName]++; +// return statement.WithTrailingTrivia(TriviaList(Comment($"/* {depth}: S#{_statementsCount[typeName]}: {comment} */"))); +//#else +// return statement; +//#endif +// } /// From 548c2b3d318fb25c7d7a09ccc3939444021f339d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Sep 2021 08:55:51 -0700 Subject: [PATCH 095/149] Update --- README.md | 168 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 1cd1d45..1b1c04f 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,141 @@ -Antigen - -C# test generator and RyuJIT tester - Named after Covid-19 antigen test. - -1. Variable declaration where RHS is literal. -2. Introduce scopes so variables can be reused. -3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' -4. Added if-else statement -5. Assignment statement, /* S:Assign */ annotation -6. For-loop -7. Do-While loop -8. While loop -9. struct -10. Assignment expression -11. Initialize out, return statement -12. Method call -13. Trimmer: works for statement -14. try-catch-finally -15. switch-case -16. Environment variables list - -TODO: -- Arrays -- Various configurations -- CSEs -- Classes -- CI pipeline \ No newline at end of file +--- +layout: post +title: Antigen +subtitle: A fuzzer to test .NET's RyuJIT +tags: [fuzzing, RyuJIT] +--- + +## What is it? + +Antigen is a fuzzer that generates random C# programs on the fly to test [.NET's RyuJIT](https://github.com/Potapy4/dotnet-coreclr/blob/master/Documentation/botr/ryujit-overview.md). + +## How does it work? + +Antigen generates random C# programs and execute them in baseline and test mode. In baseline mode there is minimal optimizations enabled, while in test mode, it executes with full optimization, and some other stress switches to turn ON/OFF certain optimizations. It then compares the output of baseline and test execution and reports back the programs if their output didn't match or if there were any asserts hit during execution. + +## How does it help uncover issues? + +Most of the unit tests are handwritten and might test a specific scenario so it might be hard to catch hidden issues. Antigen, like any other fuzzers, usually generate random C# code, sometimes having long expressions and statements that might not even be written in real world code patterns but does a great stress testing of the compilers and code generation component. By fuzzing, if there is any hidden issue in code generation, either we would hit the asserts in the compiler code or worst would give different output than baseline meaning the compiler didn't generate the machine code correctly. In either way, it uncovers several compiler issues. + +## What are the examples of expressions generated? + +Antigen currently generates range of expressions: +- Literals: All primitive types like `int`, `long`, `float`, `char`, `string`, etc. +- Variable references +- Unary and Binary operations +- Assignments +- Struct and nested struct declaration and usage +- Method declaration +- Method calls + +Below is a sample expression generated by Antigen. + +```c# +s_double_10 -= ((double)(((double)(((double)(((double)(((double)(((double)(LeafMethod4() - -2)) + ((double)(s_double_10 %= ((double)((s_double_10) + 58)))))) - ((double)(double_55 += ((double)(s_double_10 + LeafMethod4())))))) % ((double)((((double)(((double)(((double)(double_55 /= ((double)((s_double_10) + 22)))) + double_28)) / ((double)((((double)(s_double_10 *= ((double)(LeafMethod4() + double_28))))) + 96))))) + 2)))) + ((double)(((double)(((double)(((double)(p_double_44 += double_55)) % ((double)((p_double_44) + 44)))) - ((double)(((double)(double_55 - p_double_44)) + ((double)(p_double_44 += double_28)))))) + ((double)(((double)(double_28 += ((double)(s_double_10 / ((double)((double_28) + 7)))))) + ((double)(((double)(double_55 % ((double)((s_double_10) + 30)))) + LeafMethod4())))))))) * ((double)(((double)(((double)(((double)(double_28 + ((double)(double_55 * LeafMethod4())))) * ((double)(double_28 /= ((double)((((double)(LeafMethod4() + double_28))) + 72)))))) * ((double)(((double)(((double)(double_28 * LeafMethod4())) % ((double)((((double)(double_55 % ((double)((LeafMethod4()) + 57))))) + 8)))) + ((double)(((double)(LeafMethod4() % ((double)((s_double_10) + 67)))) * ((double)(double_28 += s_double_10)))))))) + p_double_44)))); +``` + +Note: Antigen currently cast every right side expression to the left side variable type and there is a TODO item to get rid of them. Likewise, there is a work item to eliminate unwanted parenthesis. + +## What are the examples of statements generated? + +Antigen currently generates range of statements: +- Variable Declaration +- Assignment statements +- if-else statements +- Loops: `for`, `while-do`, `do-while` +- try-catch-finally +- switch-case + +Here is a section of program that Antigen generated: + +```c# +byte_1 &= ((byte)(s_byte_1 &= ((byte)(((byte)(s_byte_1 %= ((byte)((((byte)(((byte)(((byte)(byte_1 * s_byte_1)) % ((byte)((((byte)(s_byte_1 ^= s_byte_1))) + 96)))) % ((byte)((byte_1) + 43))))) + 77)))) + ((byte)(LeafMethod1() + ((byte)(((byte)(((byte)(s_byte_1 - s_byte_1)) / ((byte)((((byte)(LeafMethod1() * LeafMethod1()))) + 65)))) - ((byte)(((byte)(s_byte_1 / ((byte)((LeafMethod1()) + 61)))) | ((byte)(byte_1 * byte_1)))))))))))); +int __loopvar9 = s_loopInvariant - 12, __loopSecondaryVar9_0 = s_loopInvariant - 10; +do +{ + __loopvar9 += 4; + if (__loopvar9 > s_loopInvariant + 4) + break; + __loopSecondaryVar9_0 += 3; + s_double_4 %= ((double)(double_4 = LeafMethod4())); + if (bool_0) + { + int __loopvar7 = s_loopInvariant + 10; + while ((((bool)(bool_0 = ((bool)(bool_0 = bool_0)))))) + { + __loopvar7 -= 4; + if (__loopvar7 <= s_loopInvariant - 4) + break; + LeafMethod10(); + long_7 ^= ((long)(((long)(long_7 %= ((long)((((long)(((long)(((long)(long_7 & LeafMethod7())) - ((long)(long_7 = LeafMethod7())))) + ((long)(s_long_7 <<= ((int)(((int)(LeafMethod6() & LeafMethod6())) ^ ((int)(p_int_5 ^= int_6))))))))) + 90)))) * long_7)); + LeafMethod15(); + } + + LeafMethod11(); + s_uint_12 <<= s_int_6; + } + else + { + int __loopvar8 = s_loopInvariant, __loopSecondaryVar8_0 = s_loopInvariant - 10; + for (;; __loopSecondaryVar8_0 += 3) + { + __loopvar8 += 4; + if (__loopvar8 > s_loopInvariant + 16) + break; + s_sbyte_8 &= ((sbyte)(((sbyte)(sbyte_8 -= ((sbyte)(s_sbyte_8 = ((sbyte)(sbyte_8 >> ((int)(((int)(s_int_6 - LeafMethod6())) + ((int)(int_6 - LeafMethod6())))))))))) * s_sbyte_8)); + sbyte_8 /= ((sbyte)(((sbyte)(((sbyte)(LeafMethod8() << ((int)(((int)(int_6 >> 1)) % ((int)((((int)(int_6 += ((int)(LeafMethod6() & LeafMethod6()))))) + 28)))))) * ((sbyte)(((sbyte)(sbyte_8 <<= s_int_6)) % ((sbyte)((((sbyte)(sbyte_8 &= sbyte_8))) + 31)))))) ^ ((sbyte)(((sbyte)(s_sbyte_8 <<= LeafMethod6())) >> LeafMethod6())))); + s2_15.ulong_1 %= ((ulong)(ulong_13 ^ ((ulong)(((ulong)(((ulong)(ulong_13 = ((ulong)(((ulong)(s_ulong_13 -= s_ulong_13)) * ((ulong)(s2_15.ulong_1 %= ((ulong)((s2_15.ulong_1) + 51)))))))) * ((ulong)(((ulong)(s_ulong_13 % ((ulong)((((ulong)(ulong_13 &= s2_15.ulong_1))) + 10)))) / ((ulong)((LeafMethod13()) + 71)))))) * ulong_13)))); + s_int_6 &= ((int)(LeafMethod6() % ((int)((((int)(s_int_6 -= ((int)(((int)(((int)(4 | ((int)(s_int_6 |= s_int_6)))) - s_int_6)) | ((int)(((int)(((int)(s_int_6 % ((int)((1) + 26)))) ^ ((int)(int_6 ^= s_int_6)))) / ((int)((((int)(s_int_6 = ((int)(int_6 - int_6))))) + 11))))))))) + 12)))); + long_7 ^= ((long)(((long)(((long)(((long)(s_long_7 <<= ((int)(p_int_5 >>= s_int_6)))) << ((int)(int_6 -= ((int)(((int)(p_int_5 -= int_6)) % ((int)((((int)(LeafMethod6() - s_int_6))) + 22)))))))) ^ ((long)(long_7 * LeafMethod7())))) | ((long)(((long)(((long)(long_7 | long_7)) >> ((int)(s_int_6 -= LeafMethod6())))) ^ s_long_7)))); + LeafMethod10(); + uint_12 = ((uint)(uint_12 - ((uint)(((uint)(p_uint_0 |= ((uint)(p_uint_0 >>= ((int)(((int)(s_int_6 |= int_6)) >> ((int)(s_int_6 << 94)))))))) * ((uint)(((uint)(((uint)(((uint)(s_uint_12 + LeafMethod12())) / ((uint)((uint_12) + 22)))) % ((uint)((((uint)(((uint)(s_uint_12 * LeafMethod12())) % ((uint)((((uint)(s_uint_12 + LeafMethod12()))) + 51))))) + 54)))) % ((uint)((((uint)(((uint)(((uint)(uint_12 % ((uint)((LeafMethod12()) + 10)))) + ((uint)(LeafMethod12() / ((uint)((LeafMethod12()) + 66)))))) & ((uint)(s_uint_12 = ((uint)(uint_12 | uint_12))))))) + 86)))))))); + s2_15.ulong_1 &= ulong_13; + s_ushort_11 *= ushort_11; + sbyte_8 &= ((sbyte)(sbyte_8 = LeafMethod8())); + } + } + + LeafMethod3(); +} +while ((((bool)(int_6 == ((int)(((int)(((int)(int_6 * ((int)(((int)(s_int_6 /= ((int)((LeafMethod6()) + 43)))) ^ ((int)(int_6 ^= int_6)))))) & ((int)(int_6 -= ((int)(s_int_6 &= ((int)(int_6 % ((int)((p_int_5) + 21)))))))))) % ((int)((((int)(s_int_6 *= ((int)(((int)(int_6 &= ((int)(p_int_5 >> s_int_6)))) & ((int)(((int)(s_int_6 -= LeafMethod6())) ^ ((int)(LeafMethod6() | s_int_6))))))))) + 48)))))))); +``` + +There is a long list of other statements, functionality that needs to be added like having more than 1 class, single dimension and multi-dimension arrays, SIMD APIs, etc. + +## How many test cases are validated / hour? + +To recap, Antigen generates C# program, runs it using [Corerun](https://github.com/dotnet/runtime/blob/f3c705ef291ff89b53220a31d8321355471d1937/docs/workflow/testing/using-corerun.md) in baseline mode and another `Corerun` that runs in test mode. There is fair amount of improvement that can be done to this process, but for now, with this model, on a dual-core machine, with 2 threads, Antigen can generate and validate 1000 test cases / hour. + + +## Where is it used? + +Antigen is [incorporated in dotnet/runtime repository](https://github.com/dotnet/runtime/pull/59489) to run weekly and on-demand on PRs that are making changes to RyuJIT. + +## What are the real issues found? + +Below are some of the examples of .NET issues found by Antigen: + +- [`Linux/Arm: BBJ_ALWAYS block remains unvisited during dominance computation`](https://github.com/dotnet/runtime/issues/59298) +- [`Assertion failed '!nodeInfo.IsLclVarWrite() || !unusedLclVarReads.Contains(nodeInfo.LclNum())`](https://github.com/dotnet/runtime/issues/57919) +- [`Assertion failed '((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) == 0) && "ERROR: Already morphed this node!"`](https://github.com/dotnet/runtime/issues/56962) +- [`Assertion failed 'ssaNum != SsaConfig::RESERVED_SSA_NUM`](https://github.com/dotnet/runtime/issues/57916) +- [`block->bbNatLoopNum == BasicBlock::NOT_IN_LOOP`](https://github.com/dotnet/runtime/issues/56961) +- [`operand->gtUseNum == -1 during 'Generate code'`](https://github.com/dotnet/runtime/issues/56953) +- [`Assertion failed 'lvaStackPointerVar != 0xCCCCCCCC && compiler->lvaTable[lvaStackPointerVar].lvDoNotEnregister && compiler->lvaTable[lvaStackPointerVar].lvOnFrame'`](https://github.com/dotnet/runtime/pull/59759) + + +## Can we get a reduce repro code? + +Antigen also comes with a component called `Trimmer` which would trim the C# code as much as possible while still making sure that the original issue reproduces. Currently, it has very limited capability and is slow, but there are plans to improve it going forward. + +## Where is the source code? + +The source code is in [https://github.com/kunalspathak/antigen](https://github.com/kunalspathak/antigen) and contributions are welcome. + +## What's up with the name "Antigen"? + +"Antigen" name was chosen as a reminder that this tool was developed during Covid era. The name comes from one of the Covid-19 testing methodology "Rapid Antigen test (RAT)". Just as RAT was used to detect covid symptoms, Antigen tool is used to detect any issues in .NET. + +## Other tools + +[Jakob Botsch Nielsen](https://jakobbotsch.com/) has developed [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) which fuzzes C# code and find issues in .NET code. \ No newline at end of file From 726960819b22c54821fad6bff2a833d58f2538af Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Sep 2021 08:56:54 -0700 Subject: [PATCH 096/149] Update README.md --- README.md | 7 ------- progress.md | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 progress.md diff --git a/README.md b/README.md index 1b1c04f..199a462 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,3 @@ ---- -layout: post -title: Antigen -subtitle: A fuzzer to test .NET's RyuJIT -tags: [fuzzing, RyuJIT] ---- - ## What is it? Antigen is a fuzzer that generates random C# programs on the fly to test [.NET's RyuJIT](https://github.com/Potapy4/dotnet-coreclr/blob/master/Documentation/botr/ryujit-overview.md). diff --git a/progress.md b/progress.md new file mode 100644 index 0000000..1cd1d45 --- /dev/null +++ b/progress.md @@ -0,0 +1,27 @@ +Antigen + +C# test generator and RyuJIT tester - Named after Covid-19 antigen test. + +1. Variable declaration where RHS is literal. +2. Introduce scopes so variables can be reused. +3. Enable binary operation expression. TODO: '-1617745168.5M' cannot be converted to a 'ulong' +4. Added if-else statement +5. Assignment statement, /* S:Assign */ annotation +6. For-loop +7. Do-While loop +8. While loop +9. struct +10. Assignment expression +11. Initialize out, return statement +12. Method call +13. Trimmer: works for statement +14. try-catch-finally +15. switch-case +16. Environment variables list + +TODO: +- Arrays +- Various configurations +- CSEs +- Classes +- CI pipeline \ No newline at end of file From 9793036d1a32e6c7898efaa8901f98433799d963 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Sep 2021 08:58:46 -0700 Subject: [PATCH 097/149] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 199a462..7448a76 100644 --- a/README.md +++ b/README.md @@ -121,14 +121,10 @@ Below are some of the examples of .NET issues found by Antigen: Antigen also comes with a component called `Trimmer` which would trim the C# code as much as possible while still making sure that the original issue reproduces. Currently, it has very limited capability and is slow, but there are plans to improve it going forward. -## Where is the source code? - -The source code is in [https://github.com/kunalspathak/antigen](https://github.com/kunalspathak/antigen) and contributions are welcome. - ## What's up with the name "Antigen"? "Antigen" name was chosen as a reminder that this tool was developed during Covid era. The name comes from one of the Covid-19 testing methodology "Rapid Antigen test (RAT)". Just as RAT was used to detect covid symptoms, Antigen tool is used to detect any issues in .NET. -## Other tools +## Are there any other fuzzers? -[Jakob Botsch Nielsen](https://jakobbotsch.com/) has developed [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) which fuzzes C# code and find issues in .NET code. \ No newline at end of file +There are lot of fuzzers to test compilers. One of them is [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) developed by [Jakob Botsch Nielsen](https://jakobbotsch.com/). \ No newline at end of file From de40c1a28b575ead61522d1c833154e2d3c603f1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 3 Dec 2021 16:17:07 -0800 Subject: [PATCH 098/149] Add ability to specify altjit and altjit method name to TestTrimmer --- Trimmer/TestTrimmer.cs | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 187798f..0c885f9 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -22,12 +22,12 @@ namespace Trimmer public class TestTrimmer { private string _testFileToTrim; - private string _outputFolder; private static TestRunner _testRunner; private Dictionary _baselineVariables; private Dictionary _testVariables; private string _originalTestAssertion; static int s_iterId = 1; + private CommandLineOptions _opts = null; static int Main(string[] args) { @@ -49,7 +49,7 @@ public TestTrimmer(string testFileToTrim, CommandLineOptions opts) throw new Exception($"{testFileToTrim} doesn't exist."); } _testFileToTrim = testFileToTrim; - _outputFolder = opts.IssuesFolder; + _opts = opts; _testRunner = TestRunner.GetInstance(opts.CoreRunPath, opts.IssuesFolder); ParseEnvironment(); @@ -79,6 +79,16 @@ private void ParseEnvironment() { var testContents = lineContent.Replace("// TestVars: ", string.Empty).Trim(); _testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); + + if (!string.IsNullOrEmpty(_opts.AltJitName)) + { + _testVariables["COMPlus_AltJitName"] = _opts.AltJitName; + } + + if (!string.IsNullOrEmpty(_opts.AltJitMethodName)) + { + _testVariables["COMPlus_AltJit"] = _opts.AltJitMethodName; + } return; } @@ -177,18 +187,17 @@ public bool TrimExpressions() }; - //bool trimmedAtleastOne = false; - //bool trimmedInCurrIter; + bool trimmedAtleastOne = false; + bool trimmedInCurrIter; - //do - //{ - // trimmedInCurrIter = false; - // trimmedInCurrIter |= Trim(trimmerList); - // trimmedAtleastOne |= trimmedInCurrIter; - //} while (trimmedInCurrIter); + do + { + trimmedInCurrIter = false; + trimmedInCurrIter |= Trim(trimmerList); + trimmedAtleastOne |= trimmedInCurrIter; + } while (trimmedInCurrIter); - //return trimmedAtleastOne; - return Trim(trimmerList); + return trimmedAtleastOne; } public bool TrimEnvVars() @@ -476,7 +485,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< File.WriteAllText(failFile, fileContents.ToString()); _testFileToTrim = failFile; - File.Move(compileResult.AssemblyFullPath, Path.Combine(_outputFolder, $"{failedFileName}.exe"), overwrite: true); + File.Move(compileResult.AssemblyFullPath, Path.Combine(_opts.IssuesFolder, $"{failedFileName}.exe"), overwrite: true); return verificationResult; } } @@ -494,5 +503,8 @@ public class CommandLineOptions [Option(shortName: 'j', longName: "AltJitName", Required = false, HelpText = "Name of altjit. By default, current OS/arch.")] public string AltJitName { get; set; } + + [Option(shortName: 'm', longName: "AltJitMethodName", Required = false, HelpText = "Name of method for altjit. By default, current OS/arch.")] + public string AltJitMethodName { get; set; } } } From e544a76af410c3ebbf7584c7188d87c303a72787 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 23 Feb 2022 12:05:59 -0800 Subject: [PATCH 099/149] Add OSR switches --- Antigen/Config/EnvVarOptions.cs | 46 +++++-- Antigen/Config/antigen.json | 218 ++++++++++++++++++++++++++++++++ Antigen/TestCase.cs | 2 +- 3 files changed, 257 insertions(+), 9 deletions(-) diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index 90a04c1..088ca07 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.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.Linq; namespace Antigen.Config @@ -36,9 +37,18 @@ internal static void Initialize(List baselineEnvVars, List /// - private static ComplusEnvVarGroup GetRandomTestGroup() + private static ComplusEnvVarGroup GetRandomOsrTestGroup() { - return PRNG.WeightedChoice(s_testGroupWeight); + return PRNG.WeightedChoice(s_testGroupWeight.Where(tg => tg.Data.IsOsrSwitchGroup())); + } + + /// + /// Returns a random EnvVarGroup depending on the weight. + /// + /// + private static ComplusEnvVarGroup GetRandomNonOsrTestGroup() + { + return PRNG.WeightedChoice(s_testGroupWeight.Where(tg => !tg.Data.IsOsrSwitchGroup())); } /// @@ -62,14 +72,12 @@ public static Dictionary BaseLineVars() /// Returns random set of test environment variables. /// /// - public static Dictionary TestVars() + public static Dictionary TestVars(bool includeOsrSwitches) { - var envVars = new Dictionary() - { - { "COMPlus_TieredCompilation", "0"} - }; + var envVars = new Dictionary(); var defaultGroup = s_testGroups.First(tg => tg.Name == "Default"); + // default variables var usedEnvVars = new HashSet(); var defaultVariablesCount = PRNG.Next(1, 8); @@ -86,6 +94,23 @@ public static Dictionary TestVars() envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; } + // OSR switches + if (includeOsrSwitches) + { + var osrstressGroup = GetRandomOsrTestGroup(); + // Unique OSR group found. Add all switches and move on. + foreach (var osrSwitch in osrstressGroup.Variables) + { + Debug.Assert(osrSwitch.Values.Length == 1); + envVars[$"COMPlus_{osrSwitch.Name}"] = osrSwitch.Values[0]; + } + } + else + { + envVars["COMPlus_TieredCompilation"] = "0"; + } + + // stress switches var stressVariablesCount = PRNG.Next(1, 4); for (var i = 0; i < stressVariablesCount; i++) { @@ -94,7 +119,7 @@ public static Dictionary TestVars() // Avoid duplicate variables do { - var stressGroup = GetRandomTestGroup(); + var stressGroup = GetRandomNonOsrTestGroup(); envVar = stressGroup.GetRandomVariable(); } while (!usedEnvVars.Add(envVar.Name)); @@ -165,5 +190,10 @@ public override string ToString() { return $"{Name}: {Variables.Count}"; } + + public bool IsOsrSwitchGroup() + { + return Name.Contains("OSR") || Name.Contains("PartialCompile"); + } } } diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 0ba662d..851e041 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -626,6 +626,224 @@ ] } ] + }, + { + "Name": "OSR", + "Weight": 0.2, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "OSR_Stress", + "Weight": 0.295, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_OnStackReplacement_InitialCounter", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "OSR_HitLimit", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "OSR_Stress_Random", + "Weight": 0.28, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_OnStackReplacement_InitialCounter", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "OSR_HitLimit", + "Weight": "0", /* intentially zero */ + "Values": [ "2" ] + }, + { + "Name": "JitRandomOnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "15" ] + } + ] + }, + { + "Name": "OSR_PGO", + "Weight": 0.25, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredPGO", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "PartialCompile", + "Weight": 0.25, + "Variables": [ + { + "Name": "TC_PartialCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "PartialCompile_PGO", + "Weight": 0.25, + "Variables": [ + { + "Name": "TC_PartialCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredPGO", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "OSR_PartialCompile", + "Weight": 0.258, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_PartialCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] + }, + { + "Name": "OSR_PartialCompile_PGO", + "Weight": 0.256, + "Variables": [ + { + "Name": "TC_OnStackReplacement", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_PartialCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TC_QuickJitForLoops", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredCompilation", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + }, + { + "Name": "TieredPGO", + "Weight": "0", /* intentially zero */ + "Values": [ "1" ] + } + ] } ], "Configs": [ diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 0b526c8..459bea9 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -107,7 +107,7 @@ public TestResult Verify() } #endif var baselineVariables = EnvVarOptions.BaseLineVars(); - var testVariables = EnvVarOptions.TestVars(); + var testVariables = EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3)); // Execute test first and see if we have any errors/asserts var test = s_testRunner.Execute(compileResult, testVariables, 30); From 4dab95781320f98dec42c79d970f086b43f22c80 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 28 Feb 2022 19:56:08 -0800 Subject: [PATCH 100/149] Reduce the number of unique repros created --- Antigen/TestCase.cs | 77 +++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 459bea9..514b9e8 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -2,6 +2,7 @@ using Antigen.Tree; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -28,7 +29,21 @@ public enum CompilationType }; private SyntaxNode testCaseRoot; - private static readonly Dictionary s_uniqueIssues = new(); + + private struct UniqueIssueFile + { + public readonly int UniqueIssueId; + public readonly int FileSize; + public readonly string FileName; + + public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName) + { + UniqueIssueId = _uniqueIssueId; + FileSize = _fileSize; + FileName = _fileName; + } + } + private static readonly Dictionary s_uniqueIssues = new(); internal IList> _numerals = new List>() { @@ -206,26 +221,7 @@ private void SaveTestCase( string failureText, string testFileName) { - - string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; - string uniqueIssueDirName = null; - int assertionHashCode = failureText.GetHashCode(); - lock (this) - { - if (!s_uniqueIssues.ContainsKey(assertionHashCode)) - { - s_uniqueIssues[assertionHashCode] = s_uniqueIssues.Count; - } - - // Create hash of testAssertion and copy files in respective bucket. - uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{s_uniqueIssues[assertionHashCode] }"); - if (!Directory.Exists(uniqueIssueDirName)) - { - Directory.CreateDirectory(uniqueIssueDirName); - File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), output); - } - } -#if DEBUG +#if UNREACHABLE File.Move(assemblyPath, Path.Combine(s_runOptions.OutputDirectory, $"{Name}-fail.exe"), overwrite: true); #endif @@ -272,8 +268,43 @@ private void SaveTestCase( fileContents.AppendLine(testOutput); fileContents.AppendLine("*/"); - string failFile = Path.Combine(uniqueIssueDirName, $"{testFileName}.g.cs"); - File.WriteAllText(failFile, fileContents.ToString()); + string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; + string uniqueIssueDirName = null; + int assertionHashCode = failureText.GetHashCode(); + string currentReproFile = $"{testFileName}.g.cs"; + lock (this) + { + if (!s_uniqueIssues.ContainsKey(assertionHashCode)) + { + s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile); + } + + // Create hash of testAssertion and copy files in respective bucket. + uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{s_uniqueIssues[assertionHashCode].UniqueIssueId}"); + if (!Directory.Exists(uniqueIssueDirName)) + { + Directory.CreateDirectory(uniqueIssueDirName); + File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), output); + } + + // Only cache 1 file of smallest possible size. + if (s_uniqueIssues[assertionHashCode].FileSize > fileContents.Length) + { + string largerReproFile = Path.Combine(uniqueIssueDirName, s_uniqueIssues[assertionHashCode].FileName); + if (File.Exists(largerReproFile)) + { + File.Delete(largerReproFile); + } + + + // Write the smallest file + string failFile = Path.Combine(uniqueIssueDirName, currentReproFile); + File.WriteAllText(failFile, fileContents.ToString()); + + // Update the file size + s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(s_uniqueIssues.Count, fileContents.Length, currentReproFile); + } + } } } From df6f5ba17ab3e41304f5f42014921b09986334bb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 28 Feb 2022 19:57:36 -0800 Subject: [PATCH 101/149] Optimize trimmer --- Trimmer/TestTrimmer.cs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 0c885f9..5b66364 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -27,6 +27,7 @@ public class TestTrimmer private Dictionary _testVariables; private string _originalTestAssertion; static int s_iterId = 1; + static int TRIMMER_RESET_COUNT = 10; private CommandLineOptions _opts = null; static int Main(string[] args) @@ -115,7 +116,7 @@ public void TrimTree() do { trimmedAtleastOne = false; - //trimmedAtleastOne |= TrimEnvVars(); + trimmedAtleastOne |= TrimEnvVars(); trimmedAtleastOne |= TrimStatements(); trimmedAtleastOne |= TrimExpressions(); @@ -218,12 +219,12 @@ public bool TrimEnvVars() Console.Write($"{s_iterId}. Removing {envVar}={value}"); if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) == TestResult.Pass) { - Console.WriteLine(" - Success"); + Console.WriteLine(" - Revert"); _testVariables[envVar] = value; } else { - Console.WriteLine(" - Revert"); + Console.WriteLine(" - Success"); trimmedAtleastOne = true; } } @@ -254,10 +255,14 @@ private bool Trim(List trimmerList) do { trimmedInCurrIter = false; + int trimCount = 0; + int trimmerId = 0; // pick category - foreach (var trimmer in trimmerList) + while (trimmerId < trimmerList.Count) { +TRIMMER_LOOP: + var trimmer = trimmerList[trimmerId]; SyntaxNode treeBeforeTrim = recentTree, treeAfterTrim = null; // remove all @@ -366,6 +371,16 @@ private bool Trim(List trimmerList) Console.WriteLine(" - Success"); trimmedInCurrIter = true; trimmedAtleastOne = true; + trimCount++; + + if ((trimmerId != 0) && (trimCount > TRIMMER_RESET_COUNT)) + { + // If we have seen enough trimming for lower/smaller trimmer, reset to + // try out higher trimmer. + trimCount = 0; + trimmerId = 0; + goto TRIMMER_LOOP; + } } else { @@ -377,6 +392,7 @@ private bool Trim(List trimmerList) Console.WriteLine(" - Revert"); } } + trimmerId++; } } while (trimmedInCurrIter); From 851702cda8d4eae590d1a7d420461a152b1cf63a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 29 Mar 2022 12:10:38 -0700 Subject: [PATCH 102/149] Upgrade to net6.0 --- Antigen/Antigen.csproj | 2 +- Trimmer/Trimmer.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index e513e24..6e2b594 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index 8851ee1..df5ffb2 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 From d4bf9affd8d1684a98b953fe11da13d0afa43ab1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 17 Aug 2022 00:18:25 -0700 Subject: [PATCH 103/149] Fix most of the divide by zero errors --- Antigen/Helpers/Helper.cs | 6 ++-- Antigen/TestCase.cs | 10 ++++--- Antigen/TestMethod.cs | 58 +++++++++++++++++++++++++++------------ Antigen/Tree/Operators.cs | 4 +-- Utils/TestRunner.cs | 2 +- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/Antigen/Helpers/Helper.cs b/Antigen/Helpers/Helper.cs index 8248883..3facbc5 100644 --- a/Antigen/Helpers/Helper.cs +++ b/Antigen/Helpers/Helper.cs @@ -19,14 +19,14 @@ public static Expression FixDivideByZero(TestCase testCase, Tree.ValueType leftT (op.Oper == SyntaxKind.ModuloExpression)) { // To avoid divide by zero errors - var addExpression = new AssignExpression( + var bitwiseOrExpression = new AssignExpression( testCase, leftType, new ParenthsizedExpression(testCase, rhs), - Operator.ForSyntaxKind(SyntaxKind.AddExpression), + Operator.ForSyntaxKind(SyntaxKind.BitwiseOrExpression), ConstantValue.GetRandomConstantInt(1, 100)); - return new CastExpression(testCase, addExpression, leftType); + return new CastExpression(testCase, bitwiseOrExpression, leftType); } else { diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 514b9e8..26577b6 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -99,11 +99,11 @@ public TestResult Verify() CompileResult compileResult = s_testRunner.Compile(syntaxTree, Name); if (compileResult.AssemblyFullPath == null) { - // StringBuilder fileContents = new StringBuilder(); + //StringBuilder fileContents = new StringBuilder(); //fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); //fileContents.AppendLine("/*"); - //fileContents.AppendLine($"Got {compileResult.CompileErrors.Length} compiler error(s):"); + //fileContents.AppendLine($"Got {compileResult.CompileErrors.Count()} compiler error(s):"); //foreach (var error in compileResult.CompileErrors) //{ // fileContents.AppendLine(error.ToString()); @@ -125,7 +125,7 @@ public TestResult Verify() var testVariables = EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3)); // Execute test first and see if we have any errors/asserts - var test = s_testRunner.Execute(compileResult, testVariables, 30); + var test = s_testRunner.Execute(compileResult, testVariables); // If timeout, skip if (test == "TIMEOUT") @@ -157,12 +157,14 @@ public TestResult Verify() { if (test.Contains(knownError)) { + //SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-divbyzero"); + return TheTestResult(compileResult.AssemblyFullPath, test.Contains("System.OverflowException:") ? TestResult.Overflow : TestResult.DivideByZero); } } } - string baseline = s_testRunner.Execute(compileResult, baselineVariables, 30); + string baseline = s_testRunner.Execute(compileResult, baselineVariables); // If timeout, skip if (baseline == "TIMEOUT") diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 3470287..d57c666 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -316,11 +316,18 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) { Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); Tree.ValueType lhsExprType, rhsExprType; - //TODO-cleanup: Somehow combine GetRandomExprType() and GetRandomStructType() functionality - // Currently the only problem is AllStructTypes is in scope object but GetRandomExprType() is - // in AstUtils. - if (((assignOper.InputTypes & Primitive.Struct) != 0) && PRNG.Decide(0.2) && CurrentScope.NumOfStructTypes > 0) + + if (assignOper.HasFlag(OpFlags.Divide)) { + // For divide, just use 'int` type. + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; + } + else if (((assignOper.InputTypes & Primitive.Struct) != 0) && PRNG.Decide(0.2) && CurrentScope.NumOfStructTypes > 0) + { + //TODO-cleanup: Somehow combine GetRandomExprType() and GetRandomStructType() functionality + // Currently the only problem is AllStructTypes is in scope object but GetRandomExprType() is + // in AstUtils. lhsExprType = CurrentScope.AllStructTypes[PRNG.Next(CurrentScope.NumOfStructTypes)]; } else @@ -682,19 +689,30 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); - // If the return type is boolean, then take any ExprType that returns boolean. - // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. - //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, - // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and - // the literals are selected of different type ("decimal" in this example) and we get compilation error - // because they can't be casted to short. - Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); - //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); - Tree.ValueType rhsExprType = lhsExprType; - - if (op.HasFlag(OpFlags.Shift)) + Tree.ValueType lhsExprType, rhsExprType; + + if (op.HasFlag(OpFlags.Divide)) { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + // For '/' or '%' operations, just use int as dividend and divisor + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; + } + else + { + // If the return type is boolean, then take any ExprType that returns boolean. + // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. + //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, + // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and + // the literals are selected of different type ("decimal" in this example) and we get compilation error + // because they can't be casted to short. + lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); + //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + rhsExprType = lhsExprType; + + if (op.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + } } ExprKind lhsExprKind, rhsExprKind; @@ -730,7 +748,13 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep Tree.ValueType lhsExprType, rhsExprType; lhsExprType = rhsExprType = exprType; - if (assignOper.HasFlag(OpFlags.Shift)) + if (assignOper.HasFlag(OpFlags.Divide)) + { + // For divide, just use 'int` type. + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; + } + else if (assignOper.HasFlag(OpFlags.Shift)) { rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } diff --git a/Antigen/Tree/Operators.cs b/Antigen/Tree/Operators.cs index f627c8b..984a11f 100644 --- a/Antigen/Tree/Operators.cs +++ b/Antigen/Tree/Operators.cs @@ -62,7 +62,7 @@ public bool HasReturnType(Primitive valueType) new Operator(SyntaxKind.SubtractExpression, "-", "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), new Operator(SyntaxKind.MultiplyExpression, "*", "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), new Operator(SyntaxKind.DivideExpression, "/", "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), - new Operator(SyntaxKind.ModuloExpression, "%", "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(SyntaxKind.ModuloExpression, "%", "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), new Operator(SyntaxKind.LeftShiftExpression, "<<", "i<>", "i>>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), @@ -71,7 +71,7 @@ public bool HasReturnType(Primitive valueType) new Operator(SyntaxKind.SubtractAssignmentExpression, "-=", "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), new Operator(SyntaxKind.MultiplyAssignmentExpression, "*=", "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), new Operator(SyntaxKind.DivideAssignmentExpression, "/=", "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), - new Operator(SyntaxKind.ModuloAssignmentExpression, "%=", "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(SyntaxKind.ModuloAssignmentExpression, "%=", "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), new Operator(SyntaxKind.LeftShiftAssignmentExpression, "<<=", "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), new Operator(SyntaxKind.RightShiftAssignmentExpression, ">>=", "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), diff --git a/Utils/TestRunner.cs b/Utils/TestRunner.cs index af1dc0b..840d7d0 100644 --- a/Utils/TestRunner.cs +++ b/Utils/TestRunner.cs @@ -105,7 +105,7 @@ internal CompileResult Compile(SyntaxTree programTree, string assemblyName) /// Execute the compiled assembly in an environment that has . /// /// - internal string Execute(CompileResult compileResult, Dictionary environmentVariables, int timeoutInSecs) + internal string Execute(CompileResult compileResult, Dictionary environmentVariables, int timeoutInSecs = 30) { Debug.Assert(compileResult.AssemblyFullPath != null); From 58e35b9b0c484308b21e90357cf7dc5ad2d93432 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 17 Aug 2022 00:28:10 -0700 Subject: [PATCH 104/149] Fix most of the output mismatch errors --- Antigen/TestCase.cs | 2 +- Utils/TestRunner.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 26577b6..cb613f3 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -167,7 +167,7 @@ public TestResult Verify() string baseline = s_testRunner.Execute(compileResult, baselineVariables); // If timeout, skip - if (baseline == "TIMEOUT") + if (baseline == "TIMEOUT" || string.IsNullOrEmpty(baseline) || string.IsNullOrEmpty(test)) { return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); } diff --git a/Utils/TestRunner.cs b/Utils/TestRunner.cs index 840d7d0..e04bc65 100644 --- a/Utils/TestRunner.cs +++ b/Utils/TestRunner.cs @@ -218,7 +218,7 @@ internal string Execute(CompileResult compileResult, Dictionary return "TIMEOUT"; } - string finalOutput = ""; + string finalOutput = String.Empty; try { finalOutput = output.ToString(); From 0d70a3854950d9436599bbfdc81b2b763bfc6508 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 2 May 2023 07:20:27 -0700 Subject: [PATCH 105/149] Temporarily remove JitOptRepeat --- Antigen/Config/antigen.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 851e041..4ddaaea 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -344,22 +344,22 @@ "1" ] }, - { - "Name": "JitOptRepeat", - "Weight": 0.0005, - "Values": [ - "*" - ] - }, - { - "Name": "JitOptRepeatCount", - "Weight": 0.0003, - "Values": [ - "1", - "2", - "5" - ] - }, + //{ + // "Name": "JitOptRepeat", + // "Weight": 0.0005, + // "Values": [ + // "*" + // ] + //}, + //{ + // "Name": "JitOptRepeatCount", + // "Weight": 0.0003, + // "Values": [ + // "1", + // "2", + // "5" + // ] + //}, { "Name": "TailCallLoopOpt", "Weight": 0.03, From 6dec346f67aa088ec4042989ffe59f20846b8f6d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 22 Aug 2023 06:34:10 -0700 Subject: [PATCH 106/149] Add support for Intrinsic methods (#1) * Upgrade projects to VS2022 and net7.0 * Add ExecuteBaseline option * Add VectorTypes * Convert SyntaxKind to Operation enum * Add Generic methods, GetElement/WithElement fixes * Assign Vector methods result * Add probability options for VectorMethods * Reduce the weight of Vector create methods * Add StoreVectorMethodCallResultProbability * Include hardware intrinsics * Fix the compilation errors * fix some errors and adjust the weights --- Antigen.sln | 4 +- Antigen/Antigen.csproj | 2 +- Antigen/Config/ConfigOptions.cs | 129 +++++++- Antigen/Config/RunOptions.cs | 3 + Antigen/Config/antigen.json | 9 +- Antigen/Expressions/ConstantValue.cs | 33 +- Antigen/Expressions/UnaryExpression.cs | 2 +- Antigen/Helpers/Helper.cs | 10 +- Antigen/Helpers/PreGenerated.cs | 10 +- Antigen/Helpers/VectorHelpers.cs | 298 +++++++++++++++++ Antigen/PRNG.cs | 12 +- Antigen/Statements/AssignStatement.cs | 12 +- Antigen/Statements/LoopStatement.cs | 20 +- Antigen/TestCase.cs | 7 + Antigen/TestClass.cs | 127 +++++++- Antigen/TestMethod.cs | 252 +++++++-------- Antigen/Tree/AstUtils.cs | 179 +++++++++-- Antigen/Tree/Operators.cs | 214 +++++++++---- Antigen/Tree/Types.cs | 427 +++++++++++++++++++++---- Trimmer/Trimmer.csproj | 2 +- 20 files changed, 1435 insertions(+), 317 deletions(-) create mode 100644 Antigen/Helpers/VectorHelpers.cs diff --git a/Antigen.sln b/Antigen.sln index 1fc6ae6..bbeb1ea 100644 --- a/Antigen.sln +++ b/Antigen.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30410.220 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34003.232 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Antigen", "Antigen\Antigen.csproj", "{4BA8106C-4D64-4F76-AA49-3A669AB31B82}" EndProject diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index 6e2b594..9002a19 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index 74dd570..54f5187 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -16,7 +16,7 @@ public class ConfigOptions public int MaxExprDepth = 3; public int MethodCount = 3; - public int MaxStatementCount = 10; + public int MaxStatementCount = 7; public int VariablesCount = 8; public int StructCount = 2; @@ -47,15 +47,64 @@ public class ConfigOptions public double CharWeight = 0.03; public double DecimalWeight = 0.5; public double DoubleWeight = 0.4; - public double Int16Weight = 0.4; - public double Int32Weight = 0.45; - public double Int64Weight = 0.48; + public double ShortWeight = 0.4; + public double IntWeight = 0.45; + public double LongWeight = 0.48; public double SByteWeight = 0.3; - public double SingleWeight = 0.6; + public double FloatWeight = 0.6; public double StringWeight = 0.03; - public double UInt16Weight = 0.4; - public double UInt32Weight = 0.45; - public double UInt64Weight = 0.6; + public double UShortWeight = 0.4; + public double UIntWeight = 0.45; + public double ULongWeight = 0.6; + + // Vector weights + public double Vector64_ByteWeight = 0.1; + public double Vector64_SByteWeight = 0.1; + public double Vector64_ShortWeight = 0.1; + public double Vector64_UShortWeight = 0.1; + public double Vector64_IntWeight = 0.1; + public double Vector64_UIntWeight = 0.1; + public double Vector64_LongWeight = 0.1; + public double Vector64_ULongWeight = 0.1; + public double Vector64_FloatWeight = 0.1; + public double Vector64_DoubleWeight = 0.1; + + public double Vector128_ByteWeight = 0.1; + public double Vector128_SByteWeight = 0.1; + public double Vector128_ShortWeight = 0.1; + public double Vector128_UShortWeight = 0.1; + public double Vector128_IntWeight = 0.1; + public double Vector128_UIntWeight = 0.1; + public double Vector128_LongWeight = 0.1; + public double Vector128_ULongWeight = 0.1; + public double Vector128_FloatWeight = 0.1; + public double Vector128_DoubleWeight = 0.1; + + public double Vector256_ByteWeight = 0.1; + public double Vector256_SByteWeight = 0.1; + public double Vector256_ShortWeight = 0.1; + public double Vector256_UShortWeight = 0.1; + public double Vector256_IntWeight = 0.1; + public double Vector256_UIntWeight = 0.1; + public double Vector256_LongWeight = 0.1; + public double Vector256_ULongWeight = 0.1; + public double Vector256_FloatWeight = 0.1; + public double Vector256_DoubleWeight = 0.1; + + public double Vector512_ByteWeight = 0.1; + public double Vector512_SByteWeight = 0.1; + public double Vector512_ShortWeight = 0.1; + public double Vector512_UShortWeight = 0.1; + public double Vector512_IntWeight = 0.1; + public double Vector512_UIntWeight = 0.1; + public double Vector512_LongWeight = 0.1; + public double Vector512_ULongWeight = 0.1; + public double Vector512_FloatWeight = 0.1; + public double Vector512_DoubleWeight = 0.1; + + public double Vector2Weight = 0.1; + public double Vector3Weight = 0.1; + public double Vector4Weight = 0.1; // Operator weights public double UnaryPlusWeight = 1; @@ -103,6 +152,23 @@ public class ConfigOptions public double EqualsWeight = 0.8; public double NotEqualsWeight = 0.8; + public double VectorAddWeight = 0.3; + public double VectorSubtractWeight = 0.4; + public double VectorMultiplyWeight = 0.45; + public double VectorDivideWeight = 0.2; + public double VectorBitwiseAndWeight = 0.37; + public double VectorBitwiseOrWeight = 0.48; + public double VectorExclusiveOrWeight = 0.34; + public double VectorUnaryPlusWeight = 0.33; + public double VectorUnaryMinusWeight = 0.12; + public double VectorBitwiseNotWeight = 0.29; + public double VectorSimpleAssignmentWeight = 0.364; + public double VectorAddAssignmentWeight = 0.341; + public double VectorSubtractAssignmentWeight = 0.24; + public double VectorMultiplyAssignmentWeight = 0.63; + public double VectorDivideAssignmentWeight = 0.2; + + /// /// Probablity of removing loop parameters -- see comments on BoundParameters in ForStatement /// @@ -210,6 +276,46 @@ public class ConfigOptions /// public int MaxCaseCounts = 4; + /// + /// Avx/Avx2 methods probability + /// + public double TraditionalMethodsProbability = 0.089; + + /// + /// Avx/Avx2 methods probability + /// + public double AvxMethodsProbability = 0.29; + + /// + /// SSE* methods probability + /// + public double SSEMethodsProbability = 0.198; + + /// + /// AdvSimd methods probability + /// + public double AdvSimdMethodsProbability = 0.35; + + /// + /// Probability in which vector methods will be included. + /// + public double VectorDataProbability = 0.5; + + /// + /// Number of methods to be included. Only relevant ifVectorMethodsProbability is non-zero. + /// + public double RegisterIntrinsicMethodsProbability = 0.4; + + /// + /// Number of methods to be invoked from Method0. Only relevant ifVectorMethodsProbability is non-zero. + /// + public double InvokeIntrinsicMethodsProbability = 0.001; + + /// + /// Probability of storing the method call results in a variable. + /// + public double StoreIntrinsicMethodCallResultProbability = 0.7; + public override string ToString() { return Name; @@ -217,15 +323,12 @@ public override string ToString() public double Lookup(Tree.ValueType type) { - string str = Enum.GetName(typeof(Microsoft.CodeAnalysis.SpecialType), type.DataType); - str = str.Replace("System_", ""); - return Lookup(str + WeightSuffix); + return type.IsVectorType ? Lookup(type.VectorType + WeightSuffix) : Lookup(type.PrimitiveType + WeightSuffix); } public double Lookup(Operator oper) { - string str = Enum.GetName(typeof(SyntaxKind), oper.Oper); - str = str.Replace("Expression", ""); + string str = Enum.GetName(typeof(Operation), oper.Oper); return Lookup(str + WeightSuffix); } diff --git a/Antigen/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs index eb145d4..d5a15d7 100644 --- a/Antigen/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -21,6 +21,9 @@ public class RunOptions // Duration to execute tests for (overrides number specified in each XML config file) public int RunDuration; + // Percent of time to execute baseline + public double ExecuteBaseline; + [NonSerialized()] public string CoreRun = null; diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 4ddaaea..0d143ab 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -3,6 +3,7 @@ "OutputDirectory": ".", "NumTestCases": -1, "RunDuration": -1, + "ExecuteBaseline": 0.3, "BaselineEnvVars": [ { "Name": "Default", @@ -890,7 +891,7 @@ }, { "Name": "ExceptionHandler", - "MaxStmtDepth": 5, + "MaxStmtDepth": 3, "MethodCount": 2, "TryCatchFinallyStatementWeight": 0.5, "CatchClausesCount": 5, @@ -915,9 +916,9 @@ "MaxCaseCounts": 10, "MaxStmtDepth": 6, "MaxStatementCount": 4, - "IfElseStatementWeight": 0.4, - "ForStatementWeight": 0.5, - "DoWhileStatementWeight": 0.5, + "IfElseStatementWeight": 0.8, + "ForStatementWeight": 0.2, + "DoWhileStatementWeight": 0.3, "WhileStatementWeight": 0.5, "SwitchStatementWeight": 0.45 } diff --git a/Antigen/Expressions/ConstantValue.cs b/Antigen/Expressions/ConstantValue.cs index 0e932e5..eae5ede 100644 --- a/Antigen/Expressions/ConstantValue.cs +++ b/Antigen/Expressions/ConstantValue.cs @@ -13,6 +13,13 @@ public class ConstantValue : Expression { public readonly string Value; + private static readonly Dictionary> s_vectorConstants = new Dictionary>() + { + { "Vector2", new List() { "One", "Zero", "UnitX", "UnitY" } }, + { "Vector3", new List() { "One", "Zero", "UnitX", "UnitY", "UnitZ" } }, + { "Vector4", new List() { "One", "Zero", "UnitW", "UnitX", "UnitY", "UnitZ" } }, + }; + protected ConstantValue(Tree.ValueType valueType, string value) : base(null) { if (valueType.PrimitiveType == Primitive.Char) @@ -56,10 +63,34 @@ public static ConstantValue GetRandomConstantInt(int min, int max) return new ConstantValue(Tree.ValueType.ForPrimitive(Primitive.Int), PRNG.Next(min, max).ToString()); } + /// + /// Return ConstantValue for `value`. + /// + /// + /// + public static ConstantValue GetConstantValue(int value) + { + return new ConstantValue(Tree.ValueType.ForPrimitive(Primitive.Int), value.ToString()); + } + public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList> numerals) { string constantValue; - if ((literalType.PrimitiveType & Primitive.Numeric) != 0) + if (literalType.IsVectorType) + { + constantValue = literalType.ToString(); + + if (literalType.IsVectorNumerics()) + { + var vectorConstantProps = s_vectorConstants[literalType.ToString()]; + constantValue += ("." + vectorConstantProps[PRNG.Next(vectorConstantProps.Count)]); + } + else + { + constantValue += (PRNG.Decide(0.5) ? ".AllBitsSet" : ".Zero"); + } + } + else if ((literalType.PrimitiveType & Primitive.Numeric) != 0) { // numeric int literalValue = PRNG.WeightedChoice(numerals); diff --git a/Antigen/Expressions/UnaryExpression.cs b/Antigen/Expressions/UnaryExpression.cs index 0dd34d7..46c479f 100644 --- a/Antigen/Expressions/UnaryExpression.cs +++ b/Antigen/Expressions/UnaryExpression.cs @@ -18,7 +18,7 @@ public UnaryExpression(TestCase testCase, Expression expression, Operator op) : { Expression = expression; Op = op; - _isPostOperation = op.Oper == SyntaxKind.PostIncrementExpression || op.Oper == SyntaxKind.PostDecrementExpression; + _isPostOperation = op.Oper == Operation.PostIncrement || op.Oper == Operation.PostDecrement; } public override string ToString() diff --git a/Antigen/Helpers/Helper.cs b/Antigen/Helpers/Helper.cs index 3facbc5..9eb91f4 100644 --- a/Antigen/Helpers/Helper.cs +++ b/Antigen/Helpers/Helper.cs @@ -13,17 +13,17 @@ public class Helper public static Expression FixDivideByZero(TestCase testCase, Tree.ValueType leftType, Operator op, Expression rhs) { if ( - (op.Oper == SyntaxKind.DivideAssignmentExpression) || - (op.Oper == SyntaxKind.DivideExpression) || - (op.Oper == SyntaxKind.ModuloAssignmentExpression) || - (op.Oper == SyntaxKind.ModuloExpression)) + (op.Oper == Operation.DivideAssignment) || + (op.Oper == Operation.Divide) || + (op.Oper == Operation.ModuloAssignment) || + (op.Oper == Operation.Modulo)) { // To avoid divide by zero errors var bitwiseOrExpression = new AssignExpression( testCase, leftType, new ParenthsizedExpression(testCase, rhs), - Operator.ForSyntaxKind(SyntaxKind.BitwiseOrExpression), + Operator.ForOperation(Operation.BitwiseOr), ConstantValue.GetRandomConstantInt(1, 100)); return new CastExpression(testCase, bitwiseOrExpression, leftType); diff --git a/Antigen/Helpers/PreGenerated.cs b/Antigen/Helpers/PreGenerated.cs index ff45583..9c7ef9d 100644 --- a/Antigen/Helpers/PreGenerated.cs +++ b/Antigen/Helpers/PreGenerated.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.Runtime.InteropServices; using System.Text; using Antigen.Statements; @@ -31,10 +32,17 @@ public static Statement UsingDirective // This file is auto-generated. // Seed: -1 // - using System; + +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.{0}; +using System.Numerics; "; + bool isArm = (RuntimeInformation.OSArchitecture == Architecture.Arm) || (RuntimeInformation.OSArchitecture == Architecture.Arm64); + + usingCode = string.Format(usingCode, isArm ? "Arm" : "X86"); s_usingStmts = new ArbitraryCodeStatement(null, usingCode); return s_usingStmts; } diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs new file mode 100644 index 0000000..3fb5856 --- /dev/null +++ b/Antigen/Helpers/VectorHelpers.cs @@ -0,0 +1,298 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Numerics; +using System.Reflection; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; + +namespace Antigen +{ + public partial class TestClass + { + + private static readonly List s_vectorGenericArgs = new() { typeof(byte), typeof(sbyte), + typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) }; + + private void GenerateVectorMethods() + { + if (!isVectorMethodsInitialized) + { + vectorMethods = new List(); + + RecordIntrinsicMethods(typeof(Vector2)); + RecordIntrinsicMethods(typeof(Vector3)); + RecordIntrinsicMethods(typeof(Vector4)); + RecordVectorCtors(typeof(Vector2)); + RecordVectorCtors(typeof(Vector3)); + RecordVectorCtors(typeof(Vector4)); + + if (Vector64.IsSupported) + { + RecordIntrinsicMethods(typeof(Vector64)); + } + if (Vector128.IsSupported) + { + RecordIntrinsicMethods(typeof(Vector128)); + } + if (Vector256.IsSupported) + { + RecordIntrinsicMethods(typeof(Vector256)); + } + //if (Vector512.IsSupported) + //{ + // RecordVectorMethods(typeof(Vector512)); + //} + + if (PRNG.Decide(TC.Config.TraditionalMethodsProbability)) + { + if (System.Runtime.Intrinsics.X86.Aes.IsSupported) + { + RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); + } + + if (Bmi1.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi1)); + } + if (Bmi1.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); + } + if (Bmi2.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi2)); + } + if (Bmi2.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + } + if (Fma.IsSupported) + { + RecordIntrinsicMethods(typeof(Fma)); + } + if (Lzcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt)); + } + if (Lzcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); + } + if (Pclmulqdq.IsSupported) + { + RecordIntrinsicMethods(typeof(Pclmulqdq)); + } + if (Popcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt)); + } + if (Popcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + } + } + + if (PRNG.Decide(TC.Config.AvxMethodsProbability)) + { + if (Avx.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx)); + } + if (Avx2.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx2)); + } + } + + if (PRNG.Decide(TC.Config.SSEMethodsProbability)) + { + if (Sse.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } + if (Sse2.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse2)); + } + if (Sse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse3)); + } + if (Sse41.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse41)); + } + if (Sse42.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse42)); + } + if (Ssse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } + } + + if (PRNG.Decide(TC.Config.AdvSimdMethodsProbability)) + { + if (AdvSimd.IsSupported) + { + RecordIntrinsicMethods(typeof(AdvSimd)); + } + + if (AdvSimd.Arm64.IsSupported) + { + RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + } + } + + isVectorMethodsInitialized = true; + } + + foreach (var vectorMethod in vectorMethods) + { + if (PRNG.Decide(TC.Config.RegisterIntrinsicMethodsProbability) || vectorMethod.IsVectorCreateMethod) + { + // Add all vector create methods + RegisterMethod(vectorMethod); + } + } + } + + /// + /// Record the vector methods as well as the ones that creates the Vector. + /// Applicable for Vector64, Vector128, Vector256, Vector512. + /// + /// + private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeName = null) + { + if (string.IsNullOrEmpty(vectorTypeName)) + { + vectorTypeName = vectorType.Name; + } + var methods = vectorType.GetMethods(BindingFlags.Public | BindingFlags.Static); + + foreach (var method in methods) + { + if (method.IsSpecialName) + { + // special methods like properties / operators + continue; + } + + string fullMethodName = method.ToString(); + + if (fullMethodName.Contains("IntPtr") || fullMethodName.Contains("ValueTuple") || + fullMethodName.Contains("Matrix") || fullMethodName.Contains("Span") || + fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || + fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || + fullMethodName.Contains("Vector`1") || fullMethodName.Contains("Divide") || + fullMethodName.Contains("FloatComparisonMode")) + { + // We do not support these types, so ignore these methods. + continue; + } + + if (method.IsGenericMethod) + { + if (method.GetGenericArguments().Count() == 1) + { + // Only instantiate generic single argument methods + foreach (var genericArgument in s_vectorGenericArgs) + { + var genericInitVectorMethod = method.MakeGenericMethod(genericArgument); + vectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod)); + } + } + } + else + { + vectorMethods.Add(CreateMethodSignature(vectorTypeName, method)); + } + } + } + + /// + /// Create method signature for the vectorTypeName that has the MethodInfo. + /// + /// + /// + /// Method signature + private static MethodSignature CreateMethodSignature(string vectorTypeName, MethodInfo method) + { + var ms = new MethodSignature($"{vectorTypeName}.{method.Name}", isVectorGeneric: method.IsGenericMethod, isVectorMethod: true) + { + ReturnType = Tree.ValueType.ParseType(method.ReturnType.ToString()) + }; + var containsVectorParam = false; + + foreach (var methodParameter in method.GetParameters()) + { + if (methodParameter.ParameterType.Name.StartsWith("Vector")) + { + containsVectorParam = true; + } + ms.Parameters.Add(new MethodParam() + { + ParamName = methodParameter.Name, + ParamType = Tree.ValueType.ParseType(methodParameter.ParameterType.ToString()), + PassingWay = ParamValuePassing.None + }); + } + + if ((method.Name == "Create" || method.Name == "CreateScalar") && !containsVectorParam) + { + // Ignore vector param for Create methods because we might not have those variables + // available. + ms.IsVectorCreateMethod = true; + } + + return ms; + } + + /// + /// Record the vector methods as well as the ones that creates the Vector. + /// Applicable for Vector2, Vector3, Vector4. + /// + /// + private static void RecordVectorCtors(Type vectorType) + { + var ctors = vectorType.GetConstructors(); + + foreach (var ctor in ctors) + { + string fullMethodName = ctor.ToString(); + + if (fullMethodName.Contains("IntPtr") || fullMethodName.Contains("ValueTuple") || + fullMethodName.Contains("Matrix") || fullMethodName.Contains("Span") || + fullMethodName.Contains("Quaternion") || fullMethodName.Contains("Vector")) + { + continue; + } + + var ms = new MethodSignature($"new {vectorType.Name}", isVectorGeneric: false, isVectorMethod: true, isVectorCreateMethod: true) + { + ReturnType = Tree.ValueType.ParseType(vectorType.ToString()) + }; + + foreach (var methodParameter in ctor.GetParameters()) + { + ms.Parameters.Add(new MethodParam() + { + ParamName = methodParameter.Name, + ParamType = Tree.ValueType.ParseType(methodParameter.ParameterType.ToString()), + PassingWay = ParamValuePassing.None + }); + } + + vectorMethods.Add(ms); + } + } + + } +} diff --git a/Antigen/PRNG.cs b/Antigen/PRNG.cs index 99096a7..1e426f3 100644 --- a/Antigen/PRNG.cs +++ b/Antigen/PRNG.cs @@ -16,8 +16,13 @@ public Weights(T data_, double Weight_) Data = data_; Weight = Weight_; } - }; + public override string ToString() + { + return $"{Data.ToString()} : {Weight.ToString()}"; + } + } +#pragma warning disable SYSLIB0023 public class PRNG { private static System.Security.Cryptography.RNGCryptoServiceProvider SecureRand; @@ -71,14 +76,14 @@ static public int Next(int max) static public int Next(int min, int max) { int ret; - + if (min > max) { int temp = max; max = min; min = temp; } - + if (isFixSeed) { ret = PerThreadRand[Thread.CurrentThread.ManagedThreadId].Next(min, max); @@ -223,4 +228,5 @@ public static T WeightedChoice(IEnumerable> choices) return default(T); } }; +#pragma warning restore SYSLIB0023 } diff --git a/Antigen/Statements/AssignStatement.cs b/Antigen/Statements/AssignStatement.cs index 7de9a33..18ec66a 100644 --- a/Antigen/Statements/AssignStatement.cs +++ b/Antigen/Statements/AssignStatement.cs @@ -13,11 +13,19 @@ public class AssignStatement : Statement public readonly Operator Op; public readonly Expression Right; - public AssignStatement(TestCase testCase, ValueType leftType, Expression lhs, Operator op, Expression rhs) : base(testCase) + public AssignStatement(TestCase testCase, ValueType leftType, Expression lhs, Operator op, Expression rhs, bool isVectorResult = false) : base(testCase) { Left = lhs; Op = op; - Right = Helper.FixDivideByZero(testCase, leftType, op, rhs); + + if (isVectorResult) + { + Right = rhs; + } + else + { + Right = Helper.FixDivideByZero(testCase, leftType, op, rhs); + } } public override string ToString() diff --git a/Antigen/Statements/LoopStatement.cs b/Antigen/Statements/LoopStatement.cs index 48d6181..cc42600 100644 --- a/Antigen/Statements/LoopStatement.cs +++ b/Antigen/Statements/LoopStatement.cs @@ -281,9 +281,9 @@ private Operator getLoopControlOperator(bool isFetchingForGuardCondition) Operator result = LoopParameters.LoopBreakOperator; // If break operator is '==' then guard operator is '!='. This is same regardless this is forward/backward loop - if (result.Oper == SyntaxKind.EqualsExpression && isFetchingForGuardCondition) + if (result.Oper == Operation.Equals && isFetchingForGuardCondition) { - result = Operator.ForSyntaxKind(SyntaxKind.NotEqualsExpression); // "!="; + result = Operator.ForOperation(Operation.NotEquals); // "!="; } // If this is forward loop and we are fetching for break condition, no need to flip the operator @@ -307,17 +307,17 @@ private static Operator FlipOperator(Operator oldOperator) Operator newOperator; switch (oldOperator.Oper) { - case SyntaxKind.GreaterThanExpression: // ">": - newOperator = Operator.ForSyntaxKind(SyntaxKind.LessThanExpression); // "<"; + case Operation.GreaterThan: // ">": + newOperator = Operator.ForOperation(Operation.LessThan); // "<"; break; - case SyntaxKind.LessThanExpression: // "<": - newOperator = Operator.ForSyntaxKind(SyntaxKind.GreaterThanExpression); // ">"; + case Operation.LessThan: // "<": + newOperator = Operator.ForOperation(Operation.GreaterThan); // ">"; break; - case SyntaxKind.GreaterThanOrEqualExpression: // ">=": - newOperator = Operator.ForSyntaxKind(SyntaxKind.LessThanOrEqualExpression); // "<="; + case Operation.GreaterThanOrEqual: // ">=": + newOperator = Operator.ForOperation(Operation.LessThanOrEqual); // "<="; break; - case SyntaxKind.LessThanOrEqualExpression: // "<=": - newOperator = Operator.ForSyntaxKind(SyntaxKind.GreaterThanOrEqualExpression); // ">="; + case Operation.LessThanOrEqual: // "<=": + newOperator = Operator.ForOperation(Operation.GreaterThanOrEqual); // ">="; break; default: newOperator = oldOperator; diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index cb613f3..08afac8 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -73,11 +73,13 @@ public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName) internal ConfigOptions Config { get; private set; } public string Name { get; private set; } public AstUtils AstUtils { get; private set; } + public bool ContainsVectorData { get; private set; } public TestCase(int testId, RunOptions runOptions) { s_runOptions = runOptions; Config = s_runOptions.Configs[PRNG.Next(s_runOptions.Configs.Count)]; + ContainsVectorData = PRNG.Decide(Config.VectorDataProbability); AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; @@ -164,6 +166,11 @@ public TestResult Verify() } } + if (!PRNG.Decide(s_runOptions.ExecuteBaseline)) + { + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + } + string baseline = s_testRunner.Execute(compileResult, baselineVariables); // If timeout, skip diff --git a/Antigen/TestClass.cs b/Antigen/TestClass.cs index 821fa0b..9a3009a 100644 --- a/Antigen/TestClass.cs +++ b/Antigen/TestClass.cs @@ -2,26 +2,34 @@ // The .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.Linq; +using System.Numerics; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.Intrinsics; using Antigen.Expressions; using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; - +using ValueType = Antigen.Tree.ValueType; namespace Antigen { /// /// Denotes the class to generate. /// - public class TestClass + public partial class TestClass { public Scope ClassScope { get; private set; } public string ClassName; public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } private List> _methods { get; set; } + private static List vectorMethods = null; + private static bool isVectorMethodsInitialized = false; private int _variableId; public string GetVariableName(Tree.ValueType variableType) @@ -44,9 +52,20 @@ public TestClass(TestCase tc, string className) _variableId = 0; } + /// + /// Register method + /// + /// public void RegisterMethod(MethodSignature methodSignature) { - _methods.Add(new Weights(methodSignature, (double)PRNG.Next(1, 100) / 100)); + double methodProb = (double)PRNG.Next(1, 100) / 100; + if (methodSignature.IsVectorCreateMethod) + { + // Further reduce the probability of vector create methods because + // they are anyway used to create the vectors. + methodProb /= 10; + } + _methods.Add(new Weights(methodSignature, methodProb)); } /// @@ -59,6 +78,16 @@ public void RegisterMethod(MethodSignature methodSignature) /// public IEnumerable> AllLeafMethods => _methods.Where(m => m.Data.IsLeaf); + /// + /// Returns all vector methods + /// + public IEnumerable> AllVectorMethods => _methods.Where(m => m.Data.IsVectorMethod); + + /// + /// Returns all vector create methods + /// + public IEnumerable> AllVectorCreateMethods => _methods.Where(m => m.Data.IsVectorCreateMethod); + /// /// Get random method that returns specfic returnType. Null if no such /// method is generated yet. @@ -73,6 +102,37 @@ public MethodSignature GetRandomMethod(Tree.ValueType returnType) return PRNG.WeightedChoice(matchingMethods); } + /// + /// Get random vector create method that returns specific returnType. + /// + /// + /// + public MethodSignature GetRandomVectorCreateMethod(Tree.ValueType returnType) + { + var matchingMethods = AllVectorCreateMethods.Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); + if (matchingMethods.Count == 0) + { + return null; + } + return PRNG.WeightedChoice(matchingMethods); + } + + /// + /// Get random vector create method that returns specific returnType. + /// + /// + /// + public MethodSignature GetRandomVectorMethod(Tree.ValueType returnType) + { + var matchingMethods = AllVectorMethods.Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); + + if (matchingMethods.Count == 0) + { + return null; + } + return PRNG.WeightedChoice(matchingMethods); + } + /// /// Gets random leaf method that returns specific returnType. Null if no such /// method is generated yet. @@ -81,6 +141,12 @@ public MethodSignature GetRandomMethod(Tree.ValueType returnType) /// public MethodSignature GetRandomLeafMethod(Tree.ValueType returnType) { + if (returnType.IsVectorType) + { + // VectorType is not marked as leaf-method. So just return from overall methods list. + return GetRandomVectorMethod(returnType); + } + var matchingMethods = AllLeafMethods.Where(m => m.Data.ReturnType.Equals(returnType)); if (matchingMethods.Count() == 0) { @@ -121,6 +187,12 @@ public ClassDeclStatement Generate() PushScope(ClassScope); List classMembers = new List(); + + if (TC.ContainsVectorData) + { + GenerateVectorMethods(); + } + classMembers.AddRange(GenerateStructs()); classMembers.AddRange(GenerateFields(isStatic: true)); classMembers.AddRange(GenerateFields(isStatic: false)); @@ -183,7 +255,7 @@ StructDeclStatement GenerateStruct(string structName, string structType, int str } else { - fieldType = GetASTUtils().GetRandomExprType(); + fieldType = GetASTUtils().GetRandomValueType(); } fieldName = GetVariableName(fieldType); @@ -246,14 +318,57 @@ private List GenerateFields(bool isStatic) foreach (Tree.ValueType variableType in Tree.ValueType.GetTypes()) { string variableName = (isStatic ? "s_" : string.Empty) + GetVariableName(variableType); - Expression rhs = ConstantValue.GetConstantValue(variableType, TC._numerals); - CurrentScope.AddLocal(variableType, variableName); fields.Add(new FieldDeclStatement(TC, variableType, variableName, rhs, isStatic)); } + if (TC.ContainsVectorData) + { + foreach (Tree.ValueType variableType in Tree.ValueType.GetVectorTypes()) + { + Debug.Assert(variableType.IsVectorType); + string variableName = (isStatic ? "s_" : string.Empty) + GetVariableName(variableType); + + Expression rhs; + if (PRNG.Decide(0.8)) + { + MethodSignature createSig = GetRandomVectorCreateMethod(variableType); + + List argumentNodes = new List(); + List passingWays = new List(); + + int parametersCount = createSig.Parameters.Count; + + for (int i = 0; i < parametersCount; i++) + { + MethodParam methodParam = createSig.Parameters[i]; + Tree.ValueType argType = methodParam.ParamType; + Debug.Assert(!argType.IsVectorType); + + Expression parameterValue = ConstantValue.GetConstantValue(argType, TC._numerals); + if (i == 0) + { + parameterValue = new CastExpression(TC, parameterValue, argType); + } + + argumentNodes.Add(parameterValue); + passingWays.Add(ParamValuePassing.None); + } + + rhs = new MethodCallExpression(createSig.MethodName, argumentNodes, passingWays); + } + else + { + rhs = ConstantValue.GetConstantValue(variableType, TC._numerals); + } + + CurrentScope.AddLocal(variableType, variableName); + fields.Add(new FieldDeclStatement(TC, variableType, variableName, rhs, isStatic)); + } + } + // TODO-TEMP initialize one variable of each struct type foreach (Tree.ValueType structType in CurrentScope.AllStructTypes) { diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index d57c666..aa7d06b 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -2,8 +2,6 @@ using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; @@ -167,11 +165,16 @@ public virtual MethodDeclStatement Generate() //TODO-future: Select any assignOper //Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); + if (nonLeafMethod.Data.IsVectorMethod && !PRNG.Decide(TC.Config.InvokeIntrinsicMethodsProbability)) + { + continue; + } + Tree.ValueType lhsType = nonLeafMethod.Data.ReturnType; var lhs = ExprHelper(ExprKind.VariableExpression, lhsType, 0); var rhs = MethodCallHelper(nonLeafMethod.Data, 0); - methodBody.Add(new AssignStatement(TC, lhsType, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs)); + methodBody.Add(new AssignStatement(TC, lhsType, lhs, Operator.ForOperation(Operation.SimpleAssignment), rhs)); } } @@ -246,7 +249,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) string variableName = _testClass.GetVariableName(variableType); - Expression rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(variableType.PrimitiveType), variableType, 0); + Expression rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(variableType), variableType, 0); CurrentScope.AddLocal(variableType, variableName); // Add all the fields to the scope @@ -266,7 +269,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) //Debug.Assert(depth <= TC.Config.MaxStmtDepth); Tree.ValueType condValueType = Tree.ValueType.ForPrimitive(Primitive.Boolean); - Expression conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), condValueType, 0); + Expression conditionExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(Primitive.Boolean), condValueType, 0); int ifcount = PRNG.Next(1, TC.Config.MaxStatementCount); List ifBody = new List(); @@ -317,7 +320,11 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(); Tree.ValueType lhsExprType, rhsExprType; - if (assignOper.HasFlag(OpFlags.Divide)) + if (assignOper.IsVectorOper) + { + lhsExprType = GetASTUtils().GetRandomVectorTypeForOperator(assignOper); + } + else if (assignOper.HasFlag(OpFlags.Divide)) { // For divide, just use 'int` type. lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); @@ -332,7 +339,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } else { - lhsExprType = GetASTUtils().GetRandomExprType(assignOper.InputTypes); + lhsExprType = GetASTUtils().GetRandomPrimitiveType(assignOper.InputTypes); } if (assignOper.HasFlag(OpFlags.Shift)) @@ -344,7 +351,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) rhsExprType = lhsExprType; } - ExprKind rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + ExprKind rhsKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, 0); Expression rhs = ExprHelper(rhsKind, rhsExprType, 0); @@ -366,7 +373,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); - var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); var loopStepCastExpr = ExprHelper(ExprKind.AssignExpression, Tree.ValueType.GetRandomType(), 0) as CastExpression; // No need to cast the assign expression inside for-loop. Additionally compiler would complain for it, so just @@ -404,7 +411,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); - var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack @@ -438,7 +445,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); - var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); + var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(Primitive.Boolean), Tree.ValueType.ForPrimitive(Primitive.Boolean), 0); //TODO-imp: AddInductionVariables //TODO-imp: ctrlFlowStack @@ -467,13 +474,12 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) case StmtKind.ReturnStatement: { Tree.ValueType returnType = MethodSignature.ReturnType; - if (returnType.PrimitiveType == Primitive.Void) + if (returnType.IsVectorType || returnType.PrimitiveType != Primitive.Void) { - return new ReturnStatement(TC, null); + Expression returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(returnType), returnType, 0); + return new ReturnStatement(TC, returnExpr); } - - Expression returnExpr = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(returnType.PrimitiveType), returnType, 0); - return new ReturnStatement(TC, returnExpr); + return new ReturnStatement(TC, null); } case StmtKind.TryCatchFinallyStatement: { @@ -581,7 +587,7 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) Primitive switchType = new Primitive[] { Primitive.Int, Primitive.Long, Primitive.Char, Primitive.String }[PRNG.Next(4)]; Tree.ValueType switchExprType = Tree.ValueType.ForPrimitive(switchType); - ExprKind switchExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(switchType); + ExprKind switchExprKind = GetASTUtils().GetRandomExpressionReturningValueType(switchType); Expression switchExpr = ExprHelper(switchExprKind, switchExprType, 0); //IList listOfCases = new List(); List>> listOfCases = new (); @@ -648,7 +654,28 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) } case StmtKind.MethodCallStatement: { - return new MethodCallStatement(TC, MethodCallHelper(_testClass.GetRandomMethod(), 0)); + MethodSignature method = _testClass.GetRandomMethod(); + Tree.ValueType methodReturnType = method.ReturnType; + + if (method.IsVectorMethod && PRNG.Decide(TC.Config.StoreIntrinsicMethodCallResultProbability)) + { + // For intrinsic methods, store the result in a variable. + if (!methodReturnType.IsVectorType && methodReturnType.PrimitiveType != Primitive.Void) + { + // Perform assignment only if the vector method returns a value. + Expression lhs = ExprHelper(ExprKind.VariableExpression, methodReturnType, 0); + Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(methodReturnType); + Expression rhs = MethodCallHelper(method, 0); + + if (assignOper.HasFlag(OpFlags.Shift) && (methodReturnType.PrimitiveType != Primitive.Int)) + { + rhs = new CastExpression(TC, rhs, Tree.ValueType.ForPrimitive(Primitive.Int)); + } + return new AssignStatement(TC, methodReturnType, lhs, assignOper, rhs, true); + } + } + + return new MethodCallStatement(TC, MethodCallHelper(method, 0)); } default: Debug.Assert(false, string.Format("Hit unknown statement type {0}", Enum.GetName(typeof(StmtKind), stmtKind))); @@ -685,46 +712,54 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep { //Debug.Assert(depth <= TC.Config.MaxExprDepth); - Primitive returnType = exprType.PrimitiveType; - - Operator op = GetASTUtils().GetRandomBinaryOperator(returnPrimitiveType: returnType); + Operator op = GetASTUtils().GetRandomBinaryOperator(exprType); Tree.ValueType lhsExprType, rhsExprType; - if (op.HasFlag(OpFlags.Divide)) + if (exprType.IsVectorType) { - // For '/' or '%' operations, just use int as dividend and divisor - lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - rhsExprType = lhsExprType; + // The vector type should match exactly. + lhsExprType = rhsExprType = exprType; } else { - // If the return type is boolean, then take any ExprType that returns boolean. - // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. - //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, - // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and - // the literals are selected of different type ("decimal" in this example) and we get compilation error - // because they can't be casted to short. - lhsExprType = GetASTUtils().GetRandomExprType(returnType == Primitive.Boolean ? op.InputTypes : returnType); - //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); - rhsExprType = lhsExprType; + Primitive returnType = exprType.PrimitiveType; - if (op.HasFlag(OpFlags.Shift)) + if (op.HasFlag(OpFlags.Divide)) { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + // For '/' or '%' operations, just use int as dividend and divisor + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; + } + else + { + // If the return type is boolean, then take any ExprType that returns boolean. + // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. + //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, + // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and + // the literals are selected of different type ("decimal" in this example) and we get compilation error + // because they can't be casted to short. + lhsExprType = GetASTUtils().GetRandomPrimitiveType(returnType == Primitive.Boolean ? op.InputTypes : returnType); + //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + rhsExprType = lhsExprType; + + if (op.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + } } } ExprKind lhsExprKind, rhsExprKind; if (depth < TC.Config.MaxExprDepth) { - lhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(lhsExprType.PrimitiveType); - rhsExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + lhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(lhsExprType); + rhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); } else { - lhsExprKind = GetRandomTerminalExpression(exprType); - rhsExprKind = GetRandomTerminalExpression(exprType); + lhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); + rhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); } // Fold arithmetic binop expressions that has constants. @@ -744,30 +779,32 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep { //Debug.Assert(depth <= TC.Config.MaxExprDepth); - Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(returnPrimitiveType: exprType.PrimitiveType); + Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(exprType); Tree.ValueType lhsExprType, rhsExprType; lhsExprType = rhsExprType = exprType; - if (assignOper.HasFlag(OpFlags.Divide)) + if (!assignOper.IsVectorOper) { - // For divide, just use 'int` type. - lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - rhsExprType = lhsExprType; - } - else if (assignOper.HasFlag(OpFlags.Shift)) - { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + if (assignOper.HasFlag(OpFlags.Divide)) + { + // For divide, just use 'int` type. + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; + } + else if (assignOper.HasFlag(OpFlags.Shift)) + { + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + } } - ExprKind rhsKind; if (depth < TC.Config.MaxExprDepth) { - rhsKind = GetASTUtils().GetRandomExpressionReturningPrimitive(rhsExprType.PrimitiveType); + rhsKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); } else { - rhsKind = GetRandomTerminalExpression(rhsExprType); + rhsKind = GetASTUtils().GetRandomTerminalExpression(_testClass, rhsExprType); } Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); @@ -806,7 +843,7 @@ public Statement VariableAssignmentHelper(Tree.ValueType exprType, string variab int noOfAttempts = TC.Config.NumOfAttemptsForExpression; do { - rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningPrimitive(exprType.PrimitiveType), exprType, 0); + rhs = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(exprType), exprType, 0); // Make sure that we do not end up with same lhs=lhs. if (lhs.ToString() != rhs.ToString()) { @@ -815,75 +852,7 @@ public Statement VariableAssignmentHelper(Tree.ValueType exprType, string variab } while (noOfAttempts++ < 5); Debug.Assert(lhs.ToString() != rhs.ToString()); - return new AssignStatement(TC, exprType, lhs, Operator.ForSyntaxKind(SyntaxKind.SimpleAssignmentExpression), rhs); - } - - /// - /// Makes sure to pick either a method call that has valid return type - /// or one of the variable or literal expression. - /// - /// - /// - private ExprKind GetRandomTerminalExpression(Tree.ValueType exprType) - { - ExprKind kind; - - int noOfAttempts = TC.Config.NumOfAttemptsForExpression; - bool found = false; - - do - { - kind = GetASTUtils().GetRandomTerminalExpression(); - switch (kind) - { - case ExprKind.LiteralExpression: - { - if (exprType.PrimitiveType != Primitive.Struct) - { - found = true; - } - break; - } - case ExprKind.VariableExpression: - { - found = true; - break; - } - case ExprKind.MethodCallExpression: - { - // If terminal expression is a method call, make sure we have a method that - // returns value of "exprType" - if (_testClass.GetRandomMethod(exprType) != null) - { - found = true; - break; - } - break; - } - default: - throw new Exception("Unsupported terminal expression"); - - } - - if (found) - { - break; - } - } while (noOfAttempts++ < 5); - - if (!found) - { - if (exprType.PrimitiveType == Primitive.Struct) - { - kind = ExprKind.VariableExpression; - } - else - { - kind = PRNG.Decide(0.7) ? ExprKind.VariableExpression : ExprKind.LiteralExpression; - } - } - - return kind; + return new AssignStatement(TC, exprType, lhs, Operator.ForOperation(Operation.SimpleAssignment), rhs); } private Expression MethodCallHelper(MethodSignature methodSig, int depth) @@ -904,11 +873,11 @@ private Expression MethodCallHelper(MethodSignature methodSig, int depth) { if (depth < TC.Config.MaxExprDepth) { - argExprKind = GetASTUtils().GetRandomExpressionReturningPrimitive(argType.PrimitiveType); + argExprKind = GetASTUtils().GetRandomExpressionReturningValueType(argType); } else { - argExprKind = GetRandomTerminalExpression(argType); + argExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, argType); } } else @@ -918,6 +887,31 @@ private Expression MethodCallHelper(MethodSignature methodSig, int depth) Expression argExpr = ExprHelper(argExprKind, argType, depth + 1); + if (methodSig.IsVectorMethod && !argType.IsVectorType) + { + if ((methodSig.MethodName.Contains("GetElement") || methodSig.MethodName.Contains("WithElement")) && (parameter.ParamName == "index")) + { + // For GetElement/WithElement, the index should not exceed the element count. So perform modulo operation for (argExpr % ElementCount) + VectorType targetVectorType = methodSig.Parameters[0].ParamType.VectorType; + ConstantValue elementCountExpr; + if (Tree.ValueType.GetElementCount(targetVectorType) == 1) + { + elementCountExpr = ConstantValue.GetConstantValue(1); + } + else + { + elementCountExpr = ConstantValue.GetRandomConstantInt(0, Tree.ValueType.GetElementCount(targetVectorType) - 1); + } + argExpr = new BinaryExpression(TC, Tree.ValueType.ForPrimitive(Primitive.Int), argExpr, Operator.ForOperation(Operation.BitwiseAnd), elementCountExpr); + } + else if (argExpr is ConstantValue) + { + // For vector methods, if the argument type is primitive, add an explicit + // cast expression to resolve the ambiguity of the overloaded method. + argExpr = new CastExpression(TC, argExpr, argType); + } + } + passingWays.Add(parameter.PassingWay); argumentNodes.Add(argExpr); } @@ -933,7 +927,7 @@ private Tree.ValueType GetRandomExprType() } else { - return GetASTUtils().GetRandomExprType(); + return GetASTUtils().GetRandomValueType(); } } @@ -995,14 +989,20 @@ public class MethodSignature public List Parameters; public bool IsLeaf; public bool IsNoInline; + public bool IsVectorGeneric; + public bool IsVectorMethod; + public bool IsVectorCreateMethod; - public MethodSignature(string methodName, bool isLeaf = false, bool isNoInline = false) + public MethodSignature(string methodName, bool isLeaf = false, bool isNoInline = false, bool isVectorGeneric = false, bool isVectorMethod = false, bool isVectorCreateMethod = false) { MethodName = methodName; ReturnType = Tree.ValueType.ForVoid(); Parameters = new List(); IsLeaf = isLeaf; IsNoInline = isNoInline; + IsVectorGeneric = isVectorGeneric; + IsVectorMethod = isVectorMethod; + IsVectorCreateMethod = isVectorCreateMethod; } public override bool Equals(object obj) diff --git a/Antigen/Tree/AstUtils.cs b/Antigen/Tree/AstUtils.cs index 83ea6df..3729da9 100644 --- a/Antigen/Tree/AstUtils.cs +++ b/Antigen/Tree/AstUtils.cs @@ -35,6 +35,14 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) AllTypes.Add(new Weights(type, ConfigOptions.Lookup(type))); } + if (TestCase.ContainsVectorData) + { + foreach (ValueType type in ValueType.GetVectorTypes()) + { + AllTypes.Add(new Weights(type, ConfigOptions.Lookup(type))); + } + } + // Initialize statements foreach (StmtKind stmt in (StmtKind[])Enum.GetValues(typeof(StmtKind))) { @@ -57,7 +65,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize expressions foreach (ExprKind expr in (ExprKind[])Enum.GetValues(typeof(ExprKind))) { - var weight = new Weights(expr, ConfigOptions.Lookup(expr)); ; + var weight = new Weights(expr, ConfigOptions.Lookup(expr)); if (expr == ExprKind.MethodCallExpression) { MethodCallWeight = weight; @@ -76,7 +84,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) AllStructExpressions.Add(weight); } - if (expr == ExprKind.LiteralExpression || expr == ExprKind.VariableExpression || expr == ExprKind.MethodCallExpression) + if (expr == ExprKind.LiteralExpression || expr == ExprKind.VariableExpression) { AllTerminalExpressions.Add(weight); } @@ -85,7 +93,11 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) // Initialize operators foreach (Operator oper in Operator.GetOperators()) { - AllOperators.Add(new Weights(oper, ConfigOptions.Lookup(oper))); + if (TestCase.ContainsVectorData || !oper.IsVectorOper) + { + // Add vector operators only if they are allowed. + AllOperators.Add(new Weights(oper, ConfigOptions.Lookup(oper))); + } } } @@ -103,7 +115,7 @@ public void LeaveLeafMethod() } #region Random type methods - public ValueType GetRandomExprType() + public ValueType GetRandomValueType() { // Select all appropriate types IEnumerable> types = @@ -114,7 +126,7 @@ from z in AllTypes return PRNG.WeightedChoice(types); } - public ValueType GetRandomExprType(Primitive valueType) + public ValueType GetRandomPrimitiveType(Primitive valueType) { // Select all appropriate types IEnumerable> types = @@ -126,6 +138,18 @@ where z.Data.AllowedPrimitive(valueType) return PRNG.WeightedChoice(types); } + public ValueType GetRandomVectorTypeForOperator(Operator operatorForExpr) + { + // Select all appropriate types + IEnumerable> types = + from z in AllTypes + where z.Data.AllowedVector(operatorForExpr) + select z; + + // Do a weighted random choice. + return PRNG.WeightedChoice(types); + } + #endregion #region Random expression methods @@ -150,16 +174,116 @@ from z in AllTerminalExpressions return PRNG.WeightedChoice(exprs); } - public ExprKind GetRandomExpressionReturningPrimitive(Primitive returnPrimitiveType) + public ExprKind GetRandomExpressionReturningValueType(Primitive primitiveType) { IEnumerable> exprs; + // Select all appropriate expressions - if (returnPrimitiveType == Primitive.Char) + if (primitiveType == Primitive.Char) { exprs = from z in AllNonNumericExpressions select z; } - else if (returnPrimitiveType == Primitive.Struct) + else if (primitiveType == Primitive.Struct) + { + exprs = from z in AllStructExpressions + select z; + } + else + { + exprs = from z in AllExpressions + select z; + } + + // Do a weighted random choice. + return PRNG.WeightedChoice(exprs); + } + + + /// + /// Makes sure to pick either a method call that has valid return type + /// or one of the variable or literal expression. + /// + /// + /// + public ExprKind GetRandomTerminalExpression(TestClass testClass, Tree.ValueType exprType) + { + ExprKind kind; + + int noOfAttempts = ConfigOptions.NumOfAttemptsForExpression; + bool found = false; + + do + { + kind = GetRandomTerminalExpression(); + switch (kind) + { + case ExprKind.LiteralExpression: + { + if (exprType.PrimitiveType != Primitive.Struct) + { + found = true; + } + break; + } + case ExprKind.VariableExpression: + { + found = true; + break; + } + //case ExprKind.MethodCallExpression: + // { + // // If terminal expression is a method call, make sure we have a method that + // // returns value of "exprType" + // if (testClass.GetRandomMethod(exprType) != null) + // { + // found = true; + // break; + // } + // break; + // } + default: + throw new Exception("Unsupported terminal expression"); + } + + if (found) + { + break; + } + } while (noOfAttempts++ < 5); + + if (!found) + { + if (exprType.PrimitiveType == Primitive.Struct) + { + kind = ExprKind.VariableExpression; + } + else + { + kind = PRNG.Decide(0.7) ? ExprKind.VariableExpression : ExprKind.LiteralExpression; + } + } + + return kind; + } + + public ExprKind GetRandomExpressionReturningValueType(ValueType returningType) + { + IEnumerable> exprs; + + // Select all appropriate expressions + + if (returningType.IsVectorType) + { + exprs = from z in AllExpressions + select z; + } + else if (returningType.PrimitiveType == Primitive.Char) + { + exprs = from z in AllNonNumericExpressions + select z; + } + else if (returningType.PrimitiveType == Primitive.Struct) { exprs = from z in AllStructExpressions select z; @@ -211,12 +335,12 @@ from z in AllTerminalStatements #region Random operator methods - public Operator GetRandomBinaryOperator(Primitive returnPrimitiveType) + public Operator GetRandomBinaryOperator(ValueType returnType) { // Select all appropriate operators IEnumerable> ops = from z in AllOperators - where z.Data.HasFlag(OpFlags.Binary) && !z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnPrimitiveType) + where z.Data.HasFlag(OpFlags.Binary) && !z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnType) select z; // Do a weighted random choice. @@ -261,14 +385,31 @@ where z.Data.HasFlag(OpFlags.Unary) return PRNG.WeightedChoice(ops); } - public Operator GetRandomAssignmentOperator(Primitive returnPrimitiveType = Primitive.Any) + public Operator GetRandomAssignmentOperator(ValueType returnType) { - // Select all appropriate operators - IEnumerable> ops = - from z in AllOperators - where z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnPrimitiveType) - select z; + IEnumerable> ops = from z in AllOperators + where z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasReturnType(returnType) + select z; + // Do a weighted random choice. + return PRNG.WeightedChoice(ops); + } + + public Operator GetRandomAssignmentOperator() + { + IEnumerable> ops; + if (PRNG.Decide(0.5) || !TestCase.ContainsVectorData) + { + ops = from z in AllOperators + where z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasAnyPrimitiveType() + select z; + } + else + { + ops = from z in AllOperators + where z.Data.HasFlag(OpFlags.Assignment) && z.Data.HasAnyVectorType() + select z; + } // Do a weighted random choice. return PRNG.WeightedChoice(ops); } @@ -309,14 +450,14 @@ internal LoopControlParameters GetForBoundParameters() { case 0: case 1: - Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanExpression); + Ret.LoopBreakOperator = Operator.ForOperation(Operation.GreaterThan); break; case 2: case 3: - Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanOrEqualExpression); + Ret.LoopBreakOperator = Operator.ForOperation(Operation.GreaterThanOrEqual); break; case 4: - Ret.LoopBreakOperator = Operator.ForSyntaxKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.EqualsExpression); + Ret.LoopBreakOperator = Operator.ForOperation(Operation.Equals); // variation doesn't guarantee rounding which is needed with == operator. So make invariant as 0. // eg. ChangeFactor = 2, __loopvar = 3; __loopvar != (3 * 2); __loopvar += 2; We will break in 3 iterations without invariation // eg. ChangeFactor = 2, __loopvar = 3 + 1; __loopvar != (3 * 2); __loopvar += 2; We will go to infinite loop because condition is never true diff --git a/Antigen/Tree/Operators.cs b/Antigen/Tree/Operators.cs index 984a11f..de1ec95 100644 --- a/Antigen/Tree/Operators.cs +++ b/Antigen/Tree/Operators.cs @@ -19,19 +19,74 @@ public enum OpFlags String = 0x400, } - public struct Operator + public enum Operation { + UnaryPlus, + UnaryMinus, + PreIncrement, + PreDecrement, + PostIncrement, + PostDecrement, + LogicalNot, + BitwiseNot, + Add, + Subtract, + Multiply, + Divide, + Modulo, + LeftShift, + RightShift, + SimpleAssignment, + AddAssignment, + SubtractAssignment, + MultiplyAssignment, + DivideAssignment, + ModuloAssignment, + LeftShiftAssignment, + RightShiftAssignment, + LogicalAnd, + LogicalOr, + BitwiseAnd, + BitwiseOr, + ExclusiveOr, + AndAssignment, + OrAssignment, + ExclusiveOrAssignment, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, + Equals, + NotEquals, + // vector operations + VectorAdd, + VectorSubtract, + VectorMultiply, + VectorDivide, + VectorBitwiseAnd, + VectorBitwiseOr, + VectorExclusiveOr, + VectorUnaryPlus, + VectorUnaryMinus, + VectorBitwiseNot, + VectorSimpleAssignment, + VectorAddAssignment, + VectorSubtractAssignment, + VectorMultiplyAssignment, + VectorDivideAssignment, - //public string Name => Oper.ToString(); - - + } + public struct Operator + { public OpFlags Flags; public Primitive InputTypes; public Primitive ReturnType; - public SyntaxKind Oper; + public bool IsVectorIntrinsics; + public bool IsVectorNumerics; + public Operation Oper; private readonly string renderText; - private readonly string sampleOperation; + public readonly bool IsVectorOper; public bool HasFlag(OpFlags flag) { @@ -39,70 +94,117 @@ public bool HasFlag(OpFlags flag) return val; } - public bool HasReturnType(Primitive valueType) + public bool HasReturnType(ValueType valueType) { - bool val = (ReturnType & valueType) != 0; - return val; + if (valueType.IsVectorType) + { + return valueType.AllowedVector(this); + } + else + { + return (ReturnType & valueType.PrimitiveType) != 0; + } + } + + public bool HasAnyPrimitiveType() + { + return (ReturnType & Primitive.Any) != 0; + } + + public bool HasAnyVectorType() + { + return IsVectorIntrinsics || IsVectorNumerics; } private static readonly List operators = new List() { - new Operator(SyntaxKind.UnaryPlusExpression, "+", "+i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.UnaryMinusExpression, "-", "-i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), - new Operator(SyntaxKind.PreIncrementExpression, "++", "++i", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PreDecrementExpression, "--", "--i", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostIncrementExpression, "++", "i++", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.PostDecrementExpression, "--", "i--", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), - new Operator(SyntaxKind.LogicalNotExpression, "!", "!i", Primitive.Boolean, Primitive.Boolean, OpFlags.Unary | OpFlags.Logical), - new Operator(SyntaxKind.BitwiseNotExpression, "~", "~i", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), - //new Operator(SyntaxKind.TypeOfExpression, "typeof(i)", OpFlags.Unary), - - new Operator(SyntaxKind.AddExpression, "+", "i+j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.String), - new Operator(SyntaxKind.AddExpression, "+", "i concat j", Primitive.String, Primitive.String, OpFlags.Binary | OpFlags.String), - new Operator(SyntaxKind.SubtractExpression, "-", "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.MultiplyExpression, "*", "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), - new Operator(SyntaxKind.DivideExpression, "/", "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), - new Operator(SyntaxKind.ModuloExpression, "%", "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), - new Operator(SyntaxKind.LeftShiftExpression, "<<", "i<>", "i>>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), - - new Operator(SyntaxKind.SimpleAssignmentExpression, "=", "i=j", Primitive.Any | Primitive.Struct, Primitive.Any | Primitive.Struct, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.AddAssignmentExpression, "+=", "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), - new Operator(SyntaxKind.SubtractAssignmentExpression, "-=", "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.MultiplyAssignmentExpression, "*=", "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), - new Operator(SyntaxKind.DivideAssignmentExpression, "/=", "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), - new Operator(SyntaxKind.ModuloAssignmentExpression, "%=", "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), - new Operator(SyntaxKind.LeftShiftAssignmentExpression, "<<=", "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - new Operator(SyntaxKind.RightShiftAssignmentExpression, ">>=", "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), - - new Operator(SyntaxKind.LogicalAndExpression, "&&", "i&&j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), - new Operator(SyntaxKind.LogicalOrExpression, "||", "i||j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + new Operator(Operation.UnaryPlus, "+", "+i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(Operation.UnaryMinus, "-", "-i", Primitive.Numeric, Primitive.Numeric, OpFlags.Unary | OpFlags.Math), + new Operator(Operation.PreIncrement, "++", "++i", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(Operation.PreDecrement, "--", "--i", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(Operation.PostIncrement, "++", "i++", Primitive.Numeric| Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(Operation.PostDecrement, "--", "i--", Primitive.Numeric | Primitive.Char, Primitive.Numeric| Primitive.Char, OpFlags.Unary | OpFlags.Math | OpFlags.IncrementDecrement), + new Operator(Operation.LogicalNot, "!", "!i", Primitive.Boolean, Primitive.Boolean, OpFlags.Unary | OpFlags.Logical), + new Operator(Operation.BitwiseNot, "~", "~i", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), + //new Operator(Operation.TypeOf, "typeof(i)", OpFlags.Unary), + + new Operator(Operation.Add, "+", "i+j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.String), + new Operator(Operation.Add, "+", "i concat j", Primitive.String, Primitive.String, OpFlags.Binary | OpFlags.String), + new Operator(Operation.Subtract, "-", "i-j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(Operation.Multiply, "*", "i*j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math), + new Operator(Operation.Divide, "/", "i/j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), + new Operator(Operation.Modulo, "%", "i%j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide), + new Operator(Operation.LeftShift, "<<", "i<>", "i>>j", Primitive.SignedInteger| Primitive.Char, Primitive.SignedInteger, OpFlags.Binary | OpFlags.Math | OpFlags.Shift), + + new Operator(Operation.SimpleAssignment, "=", "i=j", Primitive.Any | Primitive.Struct, Primitive.Any | Primitive.Struct, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.AddAssignment, "+=", "i+=j", Primitive.Numeric | Primitive.String, Primitive.Numeric | Primitive.String, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment | OpFlags.String), + new Operator(Operation.SubtractAssignment, "-=", "i-=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.MultiplyAssignment, "*=", "i*=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.DivideAssignment, "/=", "i/=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), + new Operator(Operation.ModuloAssignment, "%=", "i%=j", Primitive.Numeric, Primitive.Numeric, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), + new Operator(Operation.LeftShiftAssignment, "<<=", "i<<=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + new Operator(Operation.RightShiftAssignment, ">>=", "i>>=j", Primitive.Integer, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Shift | OpFlags.Assignment), + + new Operator(Operation.LogicalAnd, "&&", "i&&j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), + new Operator(Operation.LogicalOr, "||", "i||j", Primitive.Boolean,Primitive.Boolean, OpFlags.Binary | OpFlags.Logical), //TODO: below can also be logical as per https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators - new Operator(SyntaxKind.BitwiseAndExpression, "&", "i&j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.BitwiseOrExpression, "|", "i|j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - new Operator(SyntaxKind.ExclusiveOrExpression, "^", "i^j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), - - new Operator(SyntaxKind.AndAssignmentExpression, "&=", "i&=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.OrAssignmentExpression, "|=", "i|=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - new Operator(SyntaxKind.ExclusiveOrAssignmentExpression, "^=", "i^=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), - - new Operator(SyntaxKind.LessThanExpression, "<", "i", "i>j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.GreaterThanOrEqualExpression, ">=", "i>=j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), - new Operator(SyntaxKind.EqualsExpression, "==", "i==j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), - new Operator(SyntaxKind.NotEqualsExpression, "!=", "i!=j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String) + new Operator(Operation.BitwiseAnd, "&", "i&j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(Operation.BitwiseOr, "|", "i|j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(Operation.ExclusiveOr, "^", "i^j", Primitive.Integer | Primitive.Char, Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + + new Operator(Operation.AndAssignment, "&=", "i&=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(Operation.OrAssignment, "|=", "i|=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + new Operator(Operation.ExclusiveOrAssignment, "^=", "i^=j", Primitive.Integer,Primitive.Integer, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise | OpFlags.Assignment), + + new Operator(Operation.LessThan, "<", "i", "i>j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(Operation.GreaterThanOrEqual, ">=", "i>=j", Primitive.Numeric | Primitive.Char, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(Operation.Equals, "==", "i==j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + new Operator(Operation.NotEquals, "!=", "i!=j", Primitive.Any, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison | OpFlags.String), + + // vector operators + new Operator(Operation.VectorAdd, "+", "i+j", true, true, OpFlags.Binary | OpFlags.Math), + new Operator(Operation.VectorSubtract, "-", "i-j", true, true, OpFlags.Binary | OpFlags.Math), + new Operator(Operation.VectorMultiply, "*", "i*j", true, true, OpFlags.Binary | OpFlags.Math), + //new Operator(Operation.VectorDivide, "/", "i/j", true, true, OpFlags.Binary | OpFlags.Math), + new Operator(Operation.VectorBitwiseAnd, "&", "i&j", true, false, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(Operation.VectorBitwiseOr, "|", "i|j", true, false, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + new Operator(Operation.VectorExclusiveOr, "^", "i^j", true, false, OpFlags.Binary | OpFlags.Math | OpFlags.Bitwise), + //new Operator(Operation.VectorEquals, "==", "i==j", VectorType.VectorT, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + //new Operator(Operation.VectorNotEquals, "!=", "i!=j", VectorType.VectorT, Primitive.Boolean, OpFlags.Binary | OpFlags.Comparison), + new Operator(Operation.VectorUnaryPlus, "+", "+i", true, false, OpFlags.Unary | OpFlags.Math), + new Operator(Operation.VectorUnaryMinus, "-", "-i", true, false, OpFlags.Unary | OpFlags.Math), + new Operator(Operation.VectorBitwiseNot, "~", "~i", true, false, OpFlags.Unary | OpFlags.Math | OpFlags.Bitwise), + new Operator(Operation.VectorSimpleAssignment, "=", "i=j", true, true, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.VectorAddAssignment, "+=", "i+=j", true, true, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.VectorSubtractAssignment, "-=", "i-=j", true, true, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + new Operator(Operation.VectorMultiplyAssignment, "*=", "i*=j", true, true, OpFlags.Binary | OpFlags.Math | OpFlags.Assignment), + //new Operator(Operation.VectorDivideAssignment, "/=", "i/=j", true, true, OpFlags.Binary | OpFlags.Math | OpFlags.Divide | OpFlags.Assignment), }; - private Operator(SyntaxKind oper, string operatorText, string operation, Primitive inputTypes, Primitive outputType, OpFlags flags) + private Operator(Operation oper, string operatorText, string operation, Primitive inputTypes, Primitive outputType, OpFlags flags) { Oper = oper; renderText = operatorText; - sampleOperation = operation; InputTypes = inputTypes; ReturnType = outputType; Flags = flags; + IsVectorOper = false; + IsVectorIntrinsics = false; + IsVectorNumerics = false; + } + + private Operator(Operation oper, string operatorText, string operation, bool isVectorIntrinsics, bool isVectorNumerics, OpFlags flags) + { + Oper = oper; + renderText = operatorText; + IsVectorIntrinsics = isVectorIntrinsics; + IsVectorNumerics = isVectorNumerics; + Flags = flags; + IsVectorOper = true; } public static List GetOperators() @@ -110,7 +212,7 @@ public static List GetOperators() return operators; } - public static Operator ForSyntaxKind(SyntaxKind operKind) + public static Operator ForOperation(Operation operKind) { return operators.First(o => o.Oper == operKind); } diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index 455dfbc..a60c539 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -1,45 +1,38 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Numerics; +using System.Runtime.Intrinsics; +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; namespace Antigen.Tree { - //public enum TypeFlags : ulong - //{ - // Void = 0x0, - // Numeric = Primitive.Byte | Primitive.Decimal | Primitive.Double | Primitive.Int16 | Primitive.Int32 | Primitive.Int64 | Primitive.SByte | Primitive.Single | Primitive.UInt16 | Primitive.UInt32 | Primitive.UInt64, - // Integer = Primitive.Byte | Primitive.SByte | Primitive.Int16 | Primitive.Int32 | Primitive.Int64 | Primitive.UInt16 | Primitive.UInt32 | Primitive.UInt64, - // Decimal = Primitive.Single | Primitive.Double | Primitive.Decimal, - // Char = Primitive.Char, - // String = Primitive.String, - // Bool = Primitive.Boolean, - // Any = Numeric | Char | String | Bool, - //} - public enum Primitive : ulong { Void = 0x0, Boolean = 0x1, Byte = 0x2, - Char = 0x4, - Decimal = 0x8, - Double = 0x10, - Short = 0x20, - Int = 0x40, + SByte = 0x4, + Short = 0x8, + UShort = 0x10, + Int = 0x20, + UInt = 0x40, Long = 0x80, - SByte = 0x100, + ULong = 0x100, + Float = 0x200, - String = 0x400, - UShort = 0x800, - UInt = 0x1000, - ULong = 0x2000, + Double = 0x400, + Decimal = 0x800, + + Char = 0x1000, + String = 0x2000, Struct = 0x4000, - Numeric = Byte | Decimal | Double | Short | Int | Long | SByte | Float | UShort | UInt | ULong, + Numeric = Byte | SByte | Short | UShort | Int | UInt | Long | ULong | Float | Double | Decimal, SignedInteger = SByte | Short | Int | Long, UnsignedInteger = Byte | UShort | UInt | ULong, Integer = SignedInteger | UnsignedInteger, @@ -47,14 +40,95 @@ public enum Primitive : ulong Any = Numeric | Char | String | Boolean, } + public enum VectorType : ulong + { + Vector64_Byte = 1, + Vector64_SByte = 2, + Vector64_Short = 3, + Vector64_UShort = 4, + Vector64_Int = 5, + Vector64_UInt = 6, + Vector64_Long = 7, + Vector64_ULong = 8, + Vector64_Float = 9, + Vector64_Double = 10, + + Vector128_Byte = 11, + Vector128_SByte = 12, + Vector128_Short = 13, + Vector128_UShort = 14, + Vector128_Int = 15, + Vector128_UInt = 16, + Vector128_Long = 17, + Vector128_ULong = 18, + Vector128_Float = 19, + Vector128_Double = 20, + + Vector256_Byte = 21, + Vector256_SByte = 22, + Vector256_Short = 23, + Vector256_UShort = 24, + Vector256_Int = 25, + Vector256_UInt = 26, + Vector256_Long = 27, + Vector256_ULong = 28, + Vector256_Float = 29, + Vector256_Double = 30, + + //Vector512_Byte, + //Vector512_SByte, + //Vector512_Short, + //Vector512_UShort, + //Vector512_Int, + //Vector512_UInt, + //Vector512_Long, + //Vector512_ULong, + //Vector512_Float, + //Vector512_Double, + + Vector2 = 31, + Vector3 = 32, + Vector4 = 33, + } + public struct ValueType { + public bool IsVectorNumerics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector2 && VectorType <= VectorType.Vector4) + { + return true; + } + } + + return false; + } + + public bool IsVectorIntrinsics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector256_Double) + { + return true; + } + } + + return false; + } + // TODO: Matrix about implicit and explicit cast public bool AllowedPrimitive(Primitive primitives) { - bool val = (primitives & PrimitiveType) != 0; - return val; + return (primitives & PrimitiveType) != 0; + } + + public bool AllowedVector(Operator operatorForExpr) + { + return (operatorForExpr.IsVectorIntrinsics && IsVectorIntrinsics()) || (operatorForExpr.IsVectorNumerics && IsVectorNumerics()); } public string TypeName @@ -66,32 +140,264 @@ public string TypeName } } + private bool isVectorType; private string _variableNameHint; private string _structTypeName; public Primitive PrimitiveType; - //private TypeFlags Flags; - public SpecialType DataType; + public VectorType VectorType; public SyntaxKind TypeKind; private string _displayText; + private ValueType(Primitive valueType, string displayText, SyntaxKind typeKind) + { + PrimitiveType = valueType; + TypeKind = typeKind; + _structTypeName = null; + _displayText = displayText; + _variableNameHint = displayText; + isVectorType = false; + VectorType = 0; + } + + private ValueType(VectorType vectorType, string displayText, string variableNameHint) + { + VectorType = vectorType; + _displayText = displayText; + _structTypeName = null; + _variableNameHint = variableNameHint; + isVectorType = true; + } + private static readonly List types = new List() { - new ValueType(Primitive.Boolean, "bool", SpecialType.System_Boolean, SyntaxKind.BoolKeyword), - new ValueType(Primitive.Byte, "byte", SpecialType.System_Byte, SyntaxKind.ByteKeyword), - new ValueType(Primitive.Char, "char", SpecialType.System_Char, SyntaxKind.CharKeyword), - new ValueType(Primitive.Decimal, "decimal", SpecialType.System_Decimal, SyntaxKind.DecimalKeyword), - new ValueType(Primitive.Double, "double", SpecialType.System_Double, SyntaxKind.DoubleKeyword), - new ValueType(Primitive.Short, "short", SpecialType.System_Int16, SyntaxKind.ShortKeyword), - new ValueType(Primitive.Int, "int", SpecialType.System_Int32, SyntaxKind.IntKeyword), - new ValueType(Primitive.Long, "long", SpecialType.System_Int64, SyntaxKind.LongKeyword), - new ValueType(Primitive.SByte, "sbyte", SpecialType.System_SByte, SyntaxKind.SByteKeyword), - new ValueType(Primitive.Float, "float", SpecialType.System_Single, SyntaxKind.FloatKeyword), - new ValueType(Primitive.String, "string", SpecialType.System_String, SyntaxKind.StringKeyword), - new ValueType(Primitive.UShort, "ushort", SpecialType.System_UInt16, SyntaxKind.UShortKeyword), - new ValueType(Primitive.UInt, "uint", SpecialType.System_UInt32, SyntaxKind.UIntKeyword), - new ValueType(Primitive.ULong, "ulong", SpecialType.System_UInt64, SyntaxKind.ULongKeyword), + new ValueType(Primitive.Boolean, "bool", SyntaxKind.BoolKeyword), + new ValueType(Primitive.Byte, "byte", SyntaxKind.ByteKeyword), + new ValueType(Primitive.Char, "char", SyntaxKind.CharKeyword), + new ValueType(Primitive.Decimal, "decimal", SyntaxKind.DecimalKeyword), + new ValueType(Primitive.Double, "double", SyntaxKind.DoubleKeyword), + new ValueType(Primitive.Short, "short" , SyntaxKind.ShortKeyword), + new ValueType(Primitive.Int, "int", SyntaxKind.IntKeyword), + new ValueType(Primitive.Long, "long", SyntaxKind.LongKeyword), + new ValueType(Primitive.SByte, "sbyte", SyntaxKind.SByteKeyword), + new ValueType(Primitive.Float, "float", SyntaxKind.FloatKeyword), + new ValueType(Primitive.String, "string", SyntaxKind.StringKeyword), + new ValueType(Primitive.UShort, "ushort", SyntaxKind.UShortKeyword), + new ValueType(Primitive.UInt, "uint", SyntaxKind.UIntKeyword), + new ValueType(Primitive.ULong, "ulong", SyntaxKind.ULongKeyword), + }; + + private static readonly List vectorTypes = new List() + { + new ValueType(VectorType.Vector64_Byte, "Vector64", "v64_byte"), + new ValueType(VectorType.Vector64_SByte, "Vector64", "v64_sbyte"), + new ValueType(VectorType.Vector64_Short, "Vector64", "v64_short"), + new ValueType(VectorType.Vector64_UShort, "Vector64", "v64_ushort"), + new ValueType(VectorType.Vector64_Int, "Vector64", "v64_int"), + new ValueType(VectorType.Vector64_UInt, "Vector64", "v64_uint"), + new ValueType(VectorType.Vector64_Long, "Vector64", "v64_long"), + new ValueType(VectorType.Vector64_ULong, "Vector64", "v64_ulong"), + new ValueType(VectorType.Vector64_Float, "Vector64", "v64_float"), + new ValueType(VectorType.Vector64_Double, "Vector64", "v64_double"), + new ValueType(VectorType.Vector128_Byte, "Vector128", "v128_byte"), + new ValueType(VectorType.Vector128_SByte, "Vector128", "v128_sbyte"), + new ValueType(VectorType.Vector128_Short, "Vector128", "v128_short"), + new ValueType(VectorType.Vector128_UShort, "Vector128", "v128_ushort"), + new ValueType(VectorType.Vector128_Int, "Vector128", "v128_int"), + new ValueType(VectorType.Vector128_UInt, "Vector128", "v128_uint"), + new ValueType(VectorType.Vector128_Long, "Vector128", "v128_long"), + new ValueType(VectorType.Vector128_ULong, "Vector128", "v128_ulong"), + new ValueType(VectorType.Vector128_Float, "Vector128", "v128_float"), + new ValueType(VectorType.Vector128_Double, "Vector128", "v128_double"), + new ValueType(VectorType.Vector256_Byte, "Vector256", "v256_byte"), + new ValueType(VectorType.Vector256_SByte, "Vector256", "v256_sbyte"), + new ValueType(VectorType.Vector256_Short, "Vector256", "v256_short"), + new ValueType(VectorType.Vector256_UShort, "Vector256", "v256_ushort"), + new ValueType(VectorType.Vector256_Int, "Vector256", "v256_int"), + new ValueType(VectorType.Vector256_UInt, "Vector256", "v256_uint"), + new ValueType(VectorType.Vector256_Long, "Vector256", "v256_long"), + new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong"), + new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float"), + new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double"), + //new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte"), + //new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte"), + //new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short"), + //new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort"), + //new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int"), + //new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint"), + //new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long"), + //new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong"), + //new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float"), + //new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double"), + new ValueType(VectorType.Vector2, "Vector2", "v2"), + new ValueType(VectorType.Vector3, "Vector3", "v3"), + new ValueType(VectorType.Vector4, "Vector4", "v4"), + }; + private static Regex vectorRegex = new Regex(@"Vector(64|128|256)`1\[(.*)\]"); + + public static ValueType ParseType(string typeName) + { + VectorType parsedVectorType; + var vectorTypeMatch = vectorRegex.Match(typeName); + if (vectorTypeMatch.Success) + { + Debug.Assert(vectorTypeMatch.Groups.Count == 3); + var vectorLength = vectorTypeMatch.Groups[1].Value; + var templateParameterType = vectorTypeMatch.Groups[2].Value; + + parsedVectorType = vectorLength switch + { + "64" => templateParameterType switch + { + "System.Byte" => VectorType.Vector64_Byte, + "System.SByte" => VectorType.Vector64_SByte, + "System.Int16" => VectorType.Vector64_Short, + "System.UInt16" => VectorType.Vector64_UShort, + "System.Int32" => VectorType.Vector64_Int, + "System.UInt32" => VectorType.Vector64_UInt, + "System.Int64" => VectorType.Vector64_Long, + "System.UInt64" => VectorType.Vector64_ULong, + "System.Single" => VectorType.Vector64_Float, + "System.Double" => VectorType.Vector64_Double, + _ => throw new Exception("Invalid template parameter for Vector64"), + }, + "128" => templateParameterType switch + { + "System.Byte" => VectorType.Vector128_Byte, + "System.SByte" => VectorType.Vector128_SByte, + "System.Int16" => VectorType.Vector128_Short, + "System.UInt16" => VectorType.Vector128_UShort, + "System.Int32" => VectorType.Vector128_Int, + "System.UInt32" => VectorType.Vector128_UInt, + "System.Int64" => VectorType.Vector128_Long, + "System.UInt64" => VectorType.Vector128_ULong, + "System.Single" => VectorType.Vector128_Float, + "System.Double" => VectorType.Vector128_Double, + _ => throw new Exception("Invalid template parameter for Vector128"), + }, + "256" => templateParameterType switch + { + "System.Byte" => VectorType.Vector256_Byte, + "System.SByte" => VectorType.Vector256_SByte, + "System.Int16" => VectorType.Vector256_Short, + "System.UInt16" => VectorType.Vector256_UShort, + "System.Int32" => VectorType.Vector256_Int, + "System.UInt32" => VectorType.Vector256_UInt, + "System.Int64" => VectorType.Vector256_Long, + "System.UInt64" => VectorType.Vector256_ULong, + "System.Single" => VectorType.Vector256_Float, + "System.Double" => VectorType.Vector256_Double, + _ => throw new Exception("Invalid template parameter for Vector256"), + }, + //"512" => templateParameterType switch + //{ + // "System.Byte" => VectorType.Vector512_Byte, + // "System.SByte" => VectorType.Vector512_SByte, + // "System.Int16" => VectorType.Vector512_Short, + // "System.UInt16" => VectorType.Vector512_UShort, + // "System.Int32" => VectorType.Vector512_Int, + // "System.UInt32" => VectorType.Vector512_UInt, + // "System.Int64" => VectorType.Vector512_Long, + // "System.UInt64" => VectorType.Vector512_ULong, + // "System.Single" => VectorType.Vector512_Float, + // "System.Double" => VectorType.Vector512_Double, + // _ => throw new Exception("Invalid template parameter for Vector512"), + //}, + _ => throw new Exception("Invalid vector length"), + }; + return vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + } + else if (typeName.Contains("System.Numerics")) + { + parsedVectorType = typeName switch + { + "System.Numerics.Vector2" => VectorType.Vector2, + "System.Numerics.Vector3" => VectorType.Vector3, + "System.Numerics.Vector4" => VectorType.Vector4, + _ => throw new Exception("Invalid vector type Vector"), + }; + return vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + } + else + { + var parsedPrimitiveType = typeName switch + { + "System.Void" => Primitive.Void, + "System.Boolean" => Primitive.Boolean, + "System.Byte" => Primitive.Byte, + "System.SByte" => Primitive.SByte, + "System.Int16" => Primitive.Short, + "System.UInt16" => Primitive.UShort, + "System.Int32" => Primitive.Int, + "System.UInt32" => Primitive.UInt, + "System.Int64" => Primitive.Long, + "System.UInt64" => Primitive.ULong, + "System.Single" => Primitive.Float, + "System.Double" => Primitive.Double, + _ => throw new Exception("Invalid typename parameter"), + }; + return types.FirstOrDefault(t => t.PrimitiveType == parsedPrimitiveType); + } + } + + /// + /// Get the number of elements for Vector type. + /// + /// + /// + public static int GetElementCount(VectorType vectorType) + { + switch (vectorType) + { + case VectorType.Vector64_Byte: return Vector64.Count; + case VectorType.Vector64_SByte: return Vector64.Count; + case VectorType.Vector64_Short: return Vector64.Count; + case VectorType.Vector64_UShort: return Vector64.Count; + case VectorType.Vector64_Int: return Vector64.Count; + case VectorType.Vector64_UInt: return Vector64.Count; + case VectorType.Vector64_Long: return Vector64.Count; + case VectorType.Vector64_ULong: return Vector64.Count; + case VectorType.Vector64_Float: return Vector64.Count; + case VectorType.Vector64_Double: return Vector64.Count; + + case VectorType.Vector128_Byte: return Vector128.Count; + case VectorType.Vector128_SByte: return Vector128.Count; + case VectorType.Vector128_Short: return Vector128.Count; + case VectorType.Vector128_UShort: return Vector128.Count; + case VectorType.Vector128_Int: return Vector128.Count; + case VectorType.Vector128_UInt: return Vector128.Count; + case VectorType.Vector128_Long: return Vector128.Count; + case VectorType.Vector128_ULong: return Vector128.Count; + case VectorType.Vector128_Float: return Vector128.Count; + case VectorType.Vector128_Double: return Vector128.Count; + + case VectorType.Vector256_Byte: return Vector256.Count; + case VectorType.Vector256_SByte: return Vector256.Count; + case VectorType.Vector256_Short: return Vector256.Count; + case VectorType.Vector256_UShort: return Vector256.Count; + case VectorType.Vector256_Int: return Vector256.Count; + case VectorType.Vector256_UInt: return Vector256.Count; + case VectorType.Vector256_Long: return Vector256.Count; + case VectorType.Vector256_ULong: return Vector256.Count; + case VectorType.Vector256_Float: return Vector256.Count; + case VectorType.Vector256_Double: return Vector256.Count; + + //case VectorType.Vector512_Byte: return Vector512.Count; + //case VectorType.Vector512_SByte: return Vector512.Count; + //case VectorType.Vector512_Short: return Vector512.Count; + //case VectorType.Vector512_UShort: return Vector512.Count; + //case VectorType.Vector512_Int: return Vector512.Count; + //case VectorType.Vector512_UInt: return Vector512.Count; + //case VectorType.Vector512_Long: return Vector512.Count; + //case VectorType.Vector512_ULong: return Vector512.Count; + //case VectorType.Vector512_Float: return Vector512.Count; + //case VectorType.Vector512_Double: return Vector512.Count + // + default: return 0; + } + } + /// /// Returns true if this ValueType can be converted to implicitely. /// @@ -168,25 +474,20 @@ public bool CanConvert(ValueType toType) public static ValueType CreateStructType(string typeName) { - var structType = new ValueType(Primitive.Struct, typeName,/* $"struct {typeName}",*/ SpecialType.None, SyntaxKind.None); + var structType = new ValueType(Primitive.Struct, typeName, SyntaxKind.None); structType._structTypeName = typeName; structType._variableNameHint = typeName.ToLower().Replace(".", "_").ToLower(); return structType; } - private ValueType(Primitive valueType, string displayText, SpecialType dataType, SyntaxKind typeKind) + public static List GetTypes() { - PrimitiveType = valueType; - DataType = dataType; - TypeKind = typeKind; - _structTypeName = null; - _displayText = displayText; - _variableNameHint = displayText; + return types; } - public static List GetTypes() + public static List GetVectorTypes() { - return types; + return vectorTypes; } public static ValueType GetRandomType() @@ -197,15 +498,15 @@ public static ValueType GetRandomType() public override bool Equals(object obj) { ValueType otherType = (ValueType)obj; - return PrimitiveType == otherType.PrimitiveType && - DataType == otherType.DataType && + bool result = otherType.isVectorType ? (VectorType == otherType.VectorType) : (PrimitiveType == otherType.PrimitiveType); + return result && TypeKind == otherType.TypeKind && _structTypeName == otherType._structTypeName; } public override int GetHashCode() { - int hashCode = PrimitiveType.GetHashCode() ^ DataType.GetHashCode() ^ TypeKind.GetHashCode(); + int hashCode = PrimitiveType.GetHashCode() ^ VectorType.GetHashCode() ^ TypeKind.GetHashCode(); if (_structTypeName != null) { hashCode ^= _structTypeName.GetHashCode(); @@ -218,7 +519,7 @@ public static ValueType ForPrimitive(Primitive primitiveType) return types.First(t => t.PrimitiveType == primitiveType); } - private static ValueType voidType = new ValueType(Primitive.Void, "void", SpecialType.System_Void, SyntaxKind.VoidKeyword); + private static ValueType voidType = new ValueType(Primitive.Void, "void", SyntaxKind.VoidKeyword); public static ValueType ForVoid() { return voidType; @@ -226,14 +527,6 @@ public static ValueType ForVoid() public string VariableNameHint() { - //if (PrimitiveType != Primitive.Struct) - //{ - // return _displayText; // Enum.GetName(typeof(SpecialType), DataType).Replace("System_", "").ToLower(); - //} - //else - //{ - // return TypeName.ToLower().Replace(".", "_").ToLower(); - //} return _variableNameHint; } @@ -242,6 +535,8 @@ public string VariableNameHint() .Where(x => x.IsSubclassOf(typeof(Exception))) .Where(n => n.FullName.StartsWith("System.") && n.FullName.LastIndexOf(".") == 6).ToList(); + public bool IsVectorType { get => isVectorType; private set => isVectorType = value; } + public override string ToString() { return _displayText; diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index df5ffb2..b7e43e7 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0 From 51a5aa8f65d6874bf99d2d5c8c601d06f9186372 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 28 Aug 2023 20:24:53 -0700 Subject: [PATCH 107/149] Vector512 (#2) * Use global lock for logging unique issues * Add coverage for Vector512 --- Antigen/Antigen.cs | 2 +- Antigen/Antigen.csproj | 2 +- Antigen/Config/ConfigOptions.cs | 20 +++--- Antigen/Helpers/VectorHelpers.cs | 8 +-- Antigen/TestCase.cs | 8 +-- Antigen/Tree/Scope.cs | 4 +- Antigen/Tree/Types.cs | 104 +++++++++++++++---------------- Trimmer/Trimmer.csproj | 2 +- 8 files changed, 72 insertions(+), 78 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 2b79a5b..90d4a00 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -13,7 +13,7 @@ namespace Antigen { class Program { - private static readonly object s_spinLock = new object(); + internal static readonly object s_spinLock = new object(); private static int totalTestCount = 0; private static readonly RunOptions s_runOptions = RunOptions.Initialize(); private static readonly Dictionary s_stats = new() diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index 9002a19..f88f9a1 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index 54f5187..d857b0b 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -91,16 +91,16 @@ public class ConfigOptions public double Vector256_FloatWeight = 0.1; public double Vector256_DoubleWeight = 0.1; - public double Vector512_ByteWeight = 0.1; - public double Vector512_SByteWeight = 0.1; - public double Vector512_ShortWeight = 0.1; - public double Vector512_UShortWeight = 0.1; - public double Vector512_IntWeight = 0.1; - public double Vector512_UIntWeight = 0.1; - public double Vector512_LongWeight = 0.1; - public double Vector512_ULongWeight = 0.1; - public double Vector512_FloatWeight = 0.1; - public double Vector512_DoubleWeight = 0.1; + public double Vector512_ByteWeight = 0.15; + public double Vector512_SByteWeight = 0.15; + public double Vector512_ShortWeight = 0.15; + public double Vector512_UShortWeight = 0.15; + public double Vector512_IntWeight = 0.15; + public double Vector512_UIntWeight = 0.15; + public double Vector512_LongWeight = 0.15; + public double Vector512_ULongWeight = 0.15; + public double Vector512_FloatWeight = 0.15; + public double Vector512_DoubleWeight = 0.15; public double Vector2Weight = 0.1; public double Vector3Weight = 0.1; diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index 3fb5856..dc36f4a 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -44,10 +44,10 @@ private void GenerateVectorMethods() { RecordIntrinsicMethods(typeof(Vector256)); } - //if (Vector512.IsSupported) - //{ - // RecordVectorMethods(typeof(Vector512)); - //} + if (Vector512.IsSupported) + { + RecordIntrinsicMethods(typeof(Vector512)); + } if (PRNG.Decide(TC.Config.TraditionalMethodsProbability)) { diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 08afac8..264d4b0 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -62,11 +62,6 @@ public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName) new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), }; - //private List classesList; - //private List methodsList; - //private List propertiesList; - //private List fieldsList; - private static TestRunner s_testRunner; private static RunOptions s_runOptions; @@ -90,7 +85,6 @@ public void Generate() { var klass = new TestClass(this, PreGenerated.MainClassName).Generate(); var finalCode = PreGenerated.UsingDirective + klass.ToString(); - testCaseRoot = CSharpSyntaxTree.ParseText(finalCode).GetRoot(); } @@ -281,7 +275,7 @@ private void SaveTestCase( string uniqueIssueDirName = null; int assertionHashCode = failureText.GetHashCode(); string currentReproFile = $"{testFileName}.g.cs"; - lock (this) + lock (Program.s_spinLock) { if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { diff --git a/Antigen/Tree/Scope.cs b/Antigen/Tree/Scope.cs index 463fd57..593b037 100644 --- a/Antigen/Tree/Scope.cs +++ b/Antigen/Tree/Scope.cs @@ -155,7 +155,7 @@ public ValueType AddStructType(string typeName, List structFields) foreach (StructField childField in childFields) { // structs present in structToFieldsMapping should have all the child fields expanded. - Debug.Assert((childField.FieldType.PrimitiveType & Primitive.Any) != 0); + //Debug.Assert((childField.FieldType.PrimitiveType & Primitive.Any) != 0); string expandedFieldName = field.FieldName + "." + childField.FieldName; @@ -165,7 +165,7 @@ public ValueType AddStructType(string typeName, List structFields) else { // else it is a primitive - Debug.Assert((field.FieldType.PrimitiveType & Primitive.Any) != 0); + //Debug.Assert((field.FieldType.PrimitiveType & Primitive.Any) != 0); //string expandedFieldName = field.FieldName + "." + childField.FieldName; diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index a60c539..d251300 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -75,20 +75,20 @@ public enum VectorType : ulong Vector256_Float = 29, Vector256_Double = 30, - //Vector512_Byte, - //Vector512_SByte, - //Vector512_Short, - //Vector512_UShort, - //Vector512_Int, - //Vector512_UInt, - //Vector512_Long, - //Vector512_ULong, - //Vector512_Float, - //Vector512_Double, - - Vector2 = 31, - Vector3 = 32, - Vector4 = 33, + Vector512_Byte = 31, + Vector512_SByte = 32, + Vector512_Short = 33, + Vector512_UShort = 34, + Vector512_Int = 35, + Vector512_UInt = 36, + Vector512_Long = 37, + Vector512_ULong = 38, + Vector512_Float = 39, + Vector512_Double = 40, + + Vector2 = 41, + Vector3 = 42, + Vector4 = 43, } public struct ValueType @@ -110,7 +110,7 @@ public bool IsVectorIntrinsics() { if (IsVectorType) { - if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector256_Double) + if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector512_Double) { return true; } @@ -146,7 +146,7 @@ public string TypeName public Primitive PrimitiveType; public VectorType VectorType; public SyntaxKind TypeKind; - private string _displayText; + private readonly string _displayText; private ValueType(Primitive valueType, string displayText, SyntaxKind typeKind) { @@ -218,23 +218,23 @@ private ValueType(VectorType vectorType, string displayText, string variableName new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong"), new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float"), new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double"), - //new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte"), - //new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte"), - //new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short"), - //new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort"), - //new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int"), - //new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint"), - //new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long"), - //new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong"), - //new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float"), - //new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double"), + new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte"), + new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte"), + new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short"), + new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort"), + new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int"), + new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint"), + new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long"), + new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong"), + new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float"), + new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double"), new ValueType(VectorType.Vector2, "Vector2", "v2"), new ValueType(VectorType.Vector3, "Vector3", "v3"), new ValueType(VectorType.Vector4, "Vector4", "v4"), }; - private static Regex vectorRegex = new Regex(@"Vector(64|128|256)`1\[(.*)\]"); + private static readonly Regex vectorRegex = new Regex(@"Vector(64|128|256|512)`1\[(.*)\]"); public static ValueType ParseType(string typeName) { @@ -290,20 +290,20 @@ public static ValueType ParseType(string typeName) "System.Double" => VectorType.Vector256_Double, _ => throw new Exception("Invalid template parameter for Vector256"), }, - //"512" => templateParameterType switch - //{ - // "System.Byte" => VectorType.Vector512_Byte, - // "System.SByte" => VectorType.Vector512_SByte, - // "System.Int16" => VectorType.Vector512_Short, - // "System.UInt16" => VectorType.Vector512_UShort, - // "System.Int32" => VectorType.Vector512_Int, - // "System.UInt32" => VectorType.Vector512_UInt, - // "System.Int64" => VectorType.Vector512_Long, - // "System.UInt64" => VectorType.Vector512_ULong, - // "System.Single" => VectorType.Vector512_Float, - // "System.Double" => VectorType.Vector512_Double, - // _ => throw new Exception("Invalid template parameter for Vector512"), - //}, + "512" => templateParameterType switch + { + "System.Byte" => VectorType.Vector512_Byte, + "System.SByte" => VectorType.Vector512_SByte, + "System.Int16" => VectorType.Vector512_Short, + "System.UInt16" => VectorType.Vector512_UShort, + "System.Int32" => VectorType.Vector512_Int, + "System.UInt32" => VectorType.Vector512_UInt, + "System.Int64" => VectorType.Vector512_Long, + "System.UInt64" => VectorType.Vector512_ULong, + "System.Single" => VectorType.Vector512_Float, + "System.Double" => VectorType.Vector512_Double, + _ => throw new Exception("Invalid template parameter for Vector512"), + }, _ => throw new Exception("Invalid vector length"), }; return vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); @@ -383,17 +383,17 @@ public static int GetElementCount(VectorType vectorType) case VectorType.Vector256_Float: return Vector256.Count; case VectorType.Vector256_Double: return Vector256.Count; - //case VectorType.Vector512_Byte: return Vector512.Count; - //case VectorType.Vector512_SByte: return Vector512.Count; - //case VectorType.Vector512_Short: return Vector512.Count; - //case VectorType.Vector512_UShort: return Vector512.Count; - //case VectorType.Vector512_Int: return Vector512.Count; - //case VectorType.Vector512_UInt: return Vector512.Count; - //case VectorType.Vector512_Long: return Vector512.Count; - //case VectorType.Vector512_ULong: return Vector512.Count; - //case VectorType.Vector512_Float: return Vector512.Count; - //case VectorType.Vector512_Double: return Vector512.Count - // + case VectorType.Vector512_Byte: return Vector512.Count; + case VectorType.Vector512_SByte: return Vector512.Count; + case VectorType.Vector512_Short: return Vector512.Count; + case VectorType.Vector512_UShort: return Vector512.Count; + case VectorType.Vector512_Int: return Vector512.Count; + case VectorType.Vector512_UInt: return Vector512.Count; + case VectorType.Vector512_Long: return Vector512.Count; + case VectorType.Vector512_ULong: return Vector512.Count; + case VectorType.Vector512_Float: return Vector512.Count; + case VectorType.Vector512_Double: return Vector512.Count; + default: return 0; } } diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index b7e43e7..aecef22 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 From b7677d630467cf39ad22a74202c38d6e6da737e4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 29 Aug 2023 06:59:22 -0700 Subject: [PATCH 108/149] Do not return outputmismatch for unsupported platform --- Antigen/TestCase.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 264d4b0..0af4d22 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -194,8 +194,14 @@ public TestResult Verify() // If baseline and test output doesn't match else if (baseline != test) { - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{ Name}-output-mismatch"); - return TheTestResult(compileResult.AssemblyFullPath, TestResult.OutputMismatch); + bool unsupportedOperationInBaseline = baseline.Contains("System.PlatformNotSupportedException"); + bool unsupportedOperationInTest = test.Contains("System.PlatformNotSupportedException"); + if (unsupportedOperationInBaseline == unsupportedOperationInTest) + { + // Only return mismatch output if both baseline/test contains "not supported" or both doesn't contain this exception. + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{Name}-output-mismatch"); + return TheTestResult(compileResult.AssemblyFullPath, TestResult.OutputMismatch); + } } return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); From 8fd8ce204d3346a2525596f3a263e9938d3f1530 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 29 Aug 2023 07:06:29 -0700 Subject: [PATCH 109/149] Add known errors --- Antigen/TestCase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 0af4d22..50b1aae 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -26,6 +26,8 @@ public enum CompilationType { "System.OverflowException: Value was either too large or too small for a Decimal.", "System.DivideByZeroException: Attempted to divide by zero.", + "isCandidateVar(fieldVarDsc) == isMultiReg", // https://github.com/dotnet/runtime/issues/85628 + "curSize < maxSplitSize", // https://github.com/dotnet/runtime/issues/91251 }; private SyntaxNode testCaseRoot; From dacf5909deee84dd00654e3773b03192244b5256 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 29 Aug 2023 22:16:12 -0700 Subject: [PATCH 110/149] Misc update for issue tracking --- Antigen/TestCase.cs | 20 ++++++++++++++++---- Utils/RslnUtilities.cs | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 50b1aae..775f4cd 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -45,7 +46,7 @@ public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName) FileName = _fileName; } } - private static readonly Dictionary s_uniqueIssues = new(); + private static readonly ConcurrentDictionary s_uniqueIssues = new(); internal IList> _numerals = new List>() { @@ -146,6 +147,13 @@ public TestResult Verify() // If test assertion if (!string.IsNullOrEmpty(testAssertion)) { + foreach (var knownError in _knownDiffs) + { + if (testAssertion.Contains(knownError)) + { + return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + } + } SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); } @@ -189,15 +197,14 @@ public TestResult Verify() // Is there assertion in baseline? if (!string.IsNullOrEmpty(baselineAssertion)) { - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); } // If baseline and test output doesn't match else if (baseline != test) { - bool unsupportedOperationInBaseline = baseline.Contains("System.PlatformNotSupportedException"); - bool unsupportedOperationInTest = test.Contains("System.PlatformNotSupportedException"); + var unsupportedOperationInBaseline = baseline.Contains("System.PlatformNotSupportedException"); + var unsupportedOperationInTest = test.Contains("System.PlatformNotSupportedException"); if (unsupportedOperationInBaseline == unsupportedOperationInTest) { // Only return mismatch output if both baseline/test contains "not supported" or both doesn't contain this exception. @@ -237,6 +244,7 @@ private void SaveTestCase( #endif StringBuilder fileContents = new StringBuilder(); + fileContents.AppendLine($"// Found by Antigen on {DateTime.Now}"); if (baselineVars != null) { fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); @@ -277,6 +285,10 @@ private void SaveTestCase( } fileContents.AppendLine(); fileContents.AppendLine(testOutput); + fileContents.AppendLine(); + fileContents.AppendLine(); + fileContents.AppendLine("GH title text:"); + fileContents.AppendLine(failureText); fileContents.AppendLine("*/"); string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; diff --git a/Utils/RslnUtilities.cs b/Utils/RslnUtilities.cs index b297a9f..859ff3f 100644 --- a/Utils/RslnUtilities.cs +++ b/Utils/RslnUtilities.cs @@ -93,7 +93,7 @@ internal static string ParseAssertionError(string output) if (assertionMatch.Success) { Debug.Assert(assertionMatch.Groups.Count == 4); - return assertionMatch.Groups[1].Value + ":" + assertionMatch.Groups[3].Value; + return $"Assertion failed '{assertionMatch.Groups[1].Value}' during '{assertionMatch.Groups[3].Value}'"; } assertionMatch = s_coreclrAssertionRegEx.Match(output); From f0668b93b8726a00b57ce7bce2b9da5163bf2afb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 30 Aug 2023 07:19:13 -0700 Subject: [PATCH 111/149] Add Avx512 related intrinsic methods (#3) * Fix the text 'Found by Antigen' * Add Avx512 support --- Antigen/Antigen.cs | 2 +- Antigen/Config/RunOptions.cs | 27 ++++++ Antigen/Helpers/VectorHelpers.cs | 46 +++++++++-- Antigen/TestCase.cs | 1 - Antigen/Tree/Types.cs | 138 ++++++++++++++++++++----------- Trimmer/TestTrimmer.cs | 21 +++++ 6 files changed, 180 insertions(+), 55 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 90d4a00..5d0ef71 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -15,7 +15,7 @@ class Program { internal static readonly object s_spinLock = new object(); private static int totalTestCount = 0; - private static readonly RunOptions s_runOptions = RunOptions.Initialize(); + internal static readonly RunOptions s_runOptions = RunOptions.Initialize(); private static readonly Dictionary s_stats = new() { { TestResult.RoslynException, 0 }, diff --git a/Antigen/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs index d5a15d7..a74a1ca 100644 --- a/Antigen/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.Intrinsics; using Newtonsoft.Json; namespace Antigen.Config @@ -33,6 +34,27 @@ public class RunOptions public List TestEnvVars; + /// + /// If this run supports Vector64. + /// + public bool SupportsVector64 { get; private set; } + + /// + /// If this run supports Vector128. + /// + public bool SupportsVector128 { get; private set; } + + /// + /// If this run supports Vector256. + /// + public bool SupportsVector256 { get; private set; } + + /// + /// If this run supports Vector512. + /// + public bool SupportsVector512 { get; private set; } + + internal static RunOptions Initialize() { string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -42,6 +64,11 @@ internal static RunOptions Initialize() var runOption = JsonConvert.DeserializeObject(File.ReadAllText(antiGenConfig)); EnvVarOptions.Initialize(runOption.BaselineEnvVars, runOption.TestEnvVars); + runOption.SupportsVector64 = Vector64.IsHardwareAccelerated; + runOption.SupportsVector128 = Vector128.IsHardwareAccelerated; + runOption.SupportsVector256 = Vector256.IsHardwareAccelerated; + runOption.SupportsVector512 = Vector512.IsHardwareAccelerated; + return runOption; } } diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index dc36f4a..fba608d 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -10,12 +10,12 @@ using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using Antigen.Tree; namespace Antigen { public partial class TestClass { - private static readonly List s_vectorGenericArgs = new() { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) }; @@ -32,19 +32,19 @@ private void GenerateVectorMethods() RecordVectorCtors(typeof(Vector3)); RecordVectorCtors(typeof(Vector4)); - if (Vector64.IsSupported) + if (Program.s_runOptions.SupportsVector64) { RecordIntrinsicMethods(typeof(Vector64)); } - if (Vector128.IsSupported) + if (Program.s_runOptions.SupportsVector128) { RecordIntrinsicMethods(typeof(Vector128)); } - if (Vector256.IsSupported) + if (Program.s_runOptions.SupportsVector256) { RecordIntrinsicMethods(typeof(Vector256)); } - if (Vector512.IsSupported) + if (Program.s_runOptions.SupportsVector512) { RecordIntrinsicMethods(typeof(Vector512)); } @@ -96,6 +96,31 @@ private void GenerateVectorMethods() { RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); } + + if (Avx512BW.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512BW)); + } + + if (Avx512CD.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512CD)); + } + + if (Avx512DQ.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512DQ)); + } + + if (Avx512F.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512F)); + } + + if (Avx512Vbmi.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512Vbmi)); + } } if (PRNG.Decide(TC.Config.AvxMethodsProbability)) @@ -198,6 +223,17 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam continue; } + string vectorsInMethod = Tree.ValueType.GetVectorList(fullMethodName); + + // If a parameter is one of the vector that is not supported, then skip this method + if (vectorsInMethod != null) + { + if (!Program.s_runOptions.SupportsVector64 && vectorsInMethod.Contains("64")) continue; + if (!Program.s_runOptions.SupportsVector128 && vectorsInMethod.Contains("128")) continue; + if (!Program.s_runOptions.SupportsVector256 && vectorsInMethod.Contains("256")) continue; + if (!Program.s_runOptions.SupportsVector512 && vectorsInMethod.Contains("512")) continue; + } + if (method.IsGenericMethod) { if (method.GetGenericArguments().Count() == 1) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 775f4cd..c8bb627 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -244,7 +244,6 @@ private void SaveTestCase( #endif StringBuilder fileContents = new StringBuilder(); - fileContents.AppendLine($"// Found by Antigen on {DateTime.Now}"); if (baselineVars != null) { fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index d251300..70b4ea3 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -186,55 +186,97 @@ private ValueType(VectorType vectorType, string displayText, string variableName new ValueType(Primitive.ULong, "ulong", SyntaxKind.ULongKeyword), }; - private static readonly List vectorTypes = new List() + private static readonly List s_vectorTypes = new(); + + static ValueType() { - new ValueType(VectorType.Vector64_Byte, "Vector64", "v64_byte"), - new ValueType(VectorType.Vector64_SByte, "Vector64", "v64_sbyte"), - new ValueType(VectorType.Vector64_Short, "Vector64", "v64_short"), - new ValueType(VectorType.Vector64_UShort, "Vector64", "v64_ushort"), - new ValueType(VectorType.Vector64_Int, "Vector64", "v64_int"), - new ValueType(VectorType.Vector64_UInt, "Vector64", "v64_uint"), - new ValueType(VectorType.Vector64_Long, "Vector64", "v64_long"), - new ValueType(VectorType.Vector64_ULong, "Vector64", "v64_ulong"), - new ValueType(VectorType.Vector64_Float, "Vector64", "v64_float"), - new ValueType(VectorType.Vector64_Double, "Vector64", "v64_double"), - new ValueType(VectorType.Vector128_Byte, "Vector128", "v128_byte"), - new ValueType(VectorType.Vector128_SByte, "Vector128", "v128_sbyte"), - new ValueType(VectorType.Vector128_Short, "Vector128", "v128_short"), - new ValueType(VectorType.Vector128_UShort, "Vector128", "v128_ushort"), - new ValueType(VectorType.Vector128_Int, "Vector128", "v128_int"), - new ValueType(VectorType.Vector128_UInt, "Vector128", "v128_uint"), - new ValueType(VectorType.Vector128_Long, "Vector128", "v128_long"), - new ValueType(VectorType.Vector128_ULong, "Vector128", "v128_ulong"), - new ValueType(VectorType.Vector128_Float, "Vector128", "v128_float"), - new ValueType(VectorType.Vector128_Double, "Vector128", "v128_double"), - new ValueType(VectorType.Vector256_Byte, "Vector256", "v256_byte"), - new ValueType(VectorType.Vector256_SByte, "Vector256", "v256_sbyte"), - new ValueType(VectorType.Vector256_Short, "Vector256", "v256_short"), - new ValueType(VectorType.Vector256_UShort, "Vector256", "v256_ushort"), - new ValueType(VectorType.Vector256_Int, "Vector256", "v256_int"), - new ValueType(VectorType.Vector256_UInt, "Vector256", "v256_uint"), - new ValueType(VectorType.Vector256_Long, "Vector256", "v256_long"), - new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong"), - new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float"), - new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double"), - new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte"), - new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte"), - new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short"), - new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort"), - new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int"), - new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint"), - new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long"), - new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong"), - new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float"), - new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double"), - new ValueType(VectorType.Vector2, "Vector2", "v2"), - new ValueType(VectorType.Vector3, "Vector3", "v3"), - new ValueType(VectorType.Vector4, "Vector4", "v4"), + if (Program.s_runOptions.SupportsVector64) + { + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Byte, "Vector64", "v64_byte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_SByte, "Vector64", "v64_sbyte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Short, "Vector64", "v64_short")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_UShort, "Vector64", "v64_ushort")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Int, "Vector64", "v64_int")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_UInt, "Vector64", "v64_uint")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Long, "Vector64", "v64_long")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_ULong, "Vector64", "v64_ulong")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Float, "Vector64", "v64_float")); + s_vectorTypes.Add(new ValueType(VectorType.Vector64_Double, "Vector64", "v64_double")); + } - }; + if (Program.s_runOptions.SupportsVector128) + { + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Byte, "Vector128", "v128_byte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_SByte, "Vector128", "v128_sbyte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Short, "Vector128", "v128_short")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_UShort, "Vector128", "v128_ushort")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Int, "Vector128", "v128_int")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_UInt, "Vector128", "v128_uint")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Long, "Vector128", "v128_long")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_ULong, "Vector128", "v128_ulong")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Float, "Vector128", "v128_float")); + s_vectorTypes.Add(new ValueType(VectorType.Vector128_Double, "Vector128", "v128_double")); + } + + if (Program.s_runOptions.SupportsVector256) + { + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Byte, "Vector256", "v256_byte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_SByte, "Vector256", "v256_sbyte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Short, "Vector256", "v256_short")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_UShort, "Vector256", "v256_ushort")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Int, "Vector256", "v256_int")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_UInt, "Vector256", "v256_uint")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Long, "Vector256", "v256_long")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float")); + s_vectorTypes.Add(new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double")); + } + + if (Program.s_runOptions.SupportsVector512) + { + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float")); + s_vectorTypes.Add(new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double")); + } + + s_vectorTypes.Add(new ValueType(VectorType.Vector2, "Vector2", "v2")); + s_vectorTypes.Add(new ValueType(VectorType.Vector3, "Vector3", "v3")); + s_vectorTypes.Add(new ValueType(VectorType.Vector4, "Vector4", "v4")); + } private static readonly Regex vectorRegex = new Regex(@"Vector(64|128|256|512)`1\[(.*)\]"); + private static readonly Regex multipleVectorsRegex = new Regex(@"Vector(64|128|256|512)`1"); + + /// + /// Returns Vector length for given type. `null` if not a VectorType. + /// + /// + /// + public static string GetVectorList(string typeName) + { + + var vectorTypeMatches = multipleVectorsRegex.Matches(typeName); + if (vectorTypeMatches.Count == 0) + { + return null; + } + + string result = "|"; + foreach (Match vectorTypeMatch in vectorTypeMatches) + { + Debug.Assert(vectorTypeMatch.Groups.Count == 2); + result += (vectorTypeMatch.Groups[1].Value + "|"); + } + + return result; + } public static ValueType ParseType(string typeName) { @@ -306,7 +348,7 @@ public static ValueType ParseType(string typeName) }, _ => throw new Exception("Invalid vector length"), }; - return vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + return s_vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); } else if (typeName.Contains("System.Numerics")) { @@ -317,7 +359,7 @@ public static ValueType ParseType(string typeName) "System.Numerics.Vector4" => VectorType.Vector4, _ => throw new Exception("Invalid vector type Vector"), }; - return vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + return s_vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); } else { @@ -487,7 +529,7 @@ public static List GetTypes() public static List GetVectorTypes() { - return vectorTypes; + return s_vectorTypes; } public static ValueType GetRandomType() diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 5b66364..75da95a 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -22,6 +22,7 @@ namespace Trimmer public class TestTrimmer { private string _testFileToTrim; + private int _sizeOfTestFileToTrim; private static TestRunner _testRunner; private Dictionary _baselineVariables; private Dictionary _testVariables; @@ -50,6 +51,7 @@ public TestTrimmer(string testFileToTrim, CommandLineOptions opts) throw new Exception($"{testFileToTrim} doesn't exist."); } _testFileToTrim = testFileToTrim; + _sizeOfTestFileToTrim = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot().ToFullString().Length; _opts = opts; _testRunner = TestRunner.GetInstance(opts.CoreRunPath, opts.IssuesFolder); @@ -463,6 +465,9 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< programContents = Regex.Replace(programContents, @"[\r\n]*$", string.Empty, RegexOptions.Multiline); StringBuilder fileContents = new StringBuilder(); + fileContents.AppendLine("// Found by Antigen"); + fileContents.AppendLine($"// Reduced from {GetReadableFileSize(_sizeOfTestFileToTrim)} to {GetReadableFileSize(programContents.Length)}."); + fileContents.AppendLine(); fileContents.AppendLine(programContents); fileContents.AppendLine("/*"); fileContents.AppendLine("Got output diff:"); @@ -504,6 +509,22 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< File.Move(compileResult.AssemblyFullPath, Path.Combine(_opts.IssuesFolder, $"{failedFileName}.exe"), overwrite: true); return verificationResult; } + + // Credits: https://stackoverflow.com/a/281679 + private static string GetReadableFileSize(double len) + { + string[] sizes = { "B", "KB", "MB", "GB", "TB" }; + int order = 0; + while (len >= 1024 && order < sizes.Length - 1) + { + order++; + len = len / 1024; + } + + // Adjust the format string to your preferences. For example "{0:0.#}{1}" would + // show a single decimal place, and no space. + return String.Format("{0:0.##} {1}", len, sizes[order]); + } } public class CommandLineOptions From 285c1d9c75a1f2db0dd1172eb955027b393416ab Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 30 Aug 2023 07:57:59 -0700 Subject: [PATCH 112/149] Lock the registration of vector methods: --- Antigen/Helpers/VectorHelpers.cs | 255 ++++++++++++++++--------------- 1 file changed, 129 insertions(+), 126 deletions(-) diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index fba608d..7dd5ecf 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -21,162 +21,165 @@ public partial class TestClass private void GenerateVectorMethods() { - if (!isVectorMethodsInitialized) + lock (Program.s_spinLock) { - vectorMethods = new List(); - - RecordIntrinsicMethods(typeof(Vector2)); - RecordIntrinsicMethods(typeof(Vector3)); - RecordIntrinsicMethods(typeof(Vector4)); - RecordVectorCtors(typeof(Vector2)); - RecordVectorCtors(typeof(Vector3)); - RecordVectorCtors(typeof(Vector4)); - - if (Program.s_runOptions.SupportsVector64) - { - RecordIntrinsicMethods(typeof(Vector64)); - } - if (Program.s_runOptions.SupportsVector128) - { - RecordIntrinsicMethods(typeof(Vector128)); - } - if (Program.s_runOptions.SupportsVector256) - { - RecordIntrinsicMethods(typeof(Vector256)); - } - if (Program.s_runOptions.SupportsVector512) + if (!isVectorMethodsInitialized) { - RecordIntrinsicMethods(typeof(Vector512)); - } + vectorMethods = new List(); - if (PRNG.Decide(TC.Config.TraditionalMethodsProbability)) - { - if (System.Runtime.Intrinsics.X86.Aes.IsSupported) - { - RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); - } + RecordIntrinsicMethods(typeof(Vector2)); + RecordIntrinsicMethods(typeof(Vector3)); + RecordIntrinsicMethods(typeof(Vector4)); + RecordVectorCtors(typeof(Vector2)); + RecordVectorCtors(typeof(Vector3)); + RecordVectorCtors(typeof(Vector4)); - if (Bmi1.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi1)); - } - if (Bmi1.X64.IsSupported) + if (Program.s_runOptions.SupportsVector64) { - RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); + RecordIntrinsicMethods(typeof(Vector64)); } - if (Bmi2.IsSupported) + if (Program.s_runOptions.SupportsVector128) { - RecordIntrinsicMethods(typeof(Bmi2)); + RecordIntrinsicMethods(typeof(Vector128)); } - if (Bmi2.X64.IsSupported) + if (Program.s_runOptions.SupportsVector256) { - RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + RecordIntrinsicMethods(typeof(Vector256)); } - if (Fma.IsSupported) + if (Program.s_runOptions.SupportsVector512) { - RecordIntrinsicMethods(typeof(Fma)); - } - if (Lzcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt)); - } - if (Lzcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); - } - if (Pclmulqdq.IsSupported) - { - RecordIntrinsicMethods(typeof(Pclmulqdq)); - } - if (Popcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt)); - } - if (Popcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + RecordIntrinsicMethods(typeof(Vector512)); } - if (Avx512BW.IsSupported) + if (PRNG.Decide(TC.Config.TraditionalMethodsProbability)) { - RecordIntrinsicMethods(typeof(Avx512BW)); - } + if (System.Runtime.Intrinsics.X86.Aes.IsSupported) + { + RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); + } - if (Avx512CD.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512CD)); - } + if (Bmi1.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi1)); + } + if (Bmi1.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); + } + if (Bmi2.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi2)); + } + if (Bmi2.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + } + if (Fma.IsSupported) + { + RecordIntrinsicMethods(typeof(Fma)); + } + if (Lzcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt)); + } + if (Lzcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); + } + if (Pclmulqdq.IsSupported) + { + RecordIntrinsicMethods(typeof(Pclmulqdq)); + } + if (Popcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt)); + } + if (Popcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + } - if (Avx512DQ.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512DQ)); - } + if (Avx512BW.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512BW)); + } - if (Avx512F.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512F)); - } + if (Avx512CD.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512CD)); + } - if (Avx512Vbmi.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512Vbmi)); - } - } + if (Avx512DQ.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512DQ)); + } - if (PRNG.Decide(TC.Config.AvxMethodsProbability)) - { - if (Avx.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx)); - } - if (Avx2.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx2)); - } - } + if (Avx512F.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512F)); + } - if (PRNG.Decide(TC.Config.SSEMethodsProbability)) - { - if (Sse.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse)); - } - if (Sse2.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse2)); - } - if (Sse3.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse3)); - } - if (Sse41.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse41)); - } - if (Sse42.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse42)); + if (Avx512Vbmi.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512Vbmi)); + } } - if (Ssse3.IsSupported) + + if (PRNG.Decide(TC.Config.AvxMethodsProbability)) { - RecordIntrinsicMethods(typeof(Sse)); + if (Avx.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx)); + } + if (Avx2.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx2)); + } } - } - if (PRNG.Decide(TC.Config.AdvSimdMethodsProbability)) - { - if (AdvSimd.IsSupported) + if (PRNG.Decide(TC.Config.SSEMethodsProbability)) { - RecordIntrinsicMethods(typeof(AdvSimd)); + if (Sse.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } + if (Sse2.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse2)); + } + if (Sse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse3)); + } + if (Sse41.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse41)); + } + if (Sse42.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse42)); + } + if (Ssse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } } - if (AdvSimd.Arm64.IsSupported) + if (PRNG.Decide(TC.Config.AdvSimdMethodsProbability)) { - RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + if (AdvSimd.IsSupported) + { + RecordIntrinsicMethods(typeof(AdvSimd)); + } + + if (AdvSimd.Arm64.IsSupported) + { + RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + } } - } - isVectorMethodsInitialized = true; + isVectorMethodsInitialized = true; + } } foreach (var vectorMethod in vectorMethods) From 35e7032ac179ef3e1d77672231237a681bb453f8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 31 Aug 2023 19:25:14 -0700 Subject: [PATCH 113/149] Move Avx* methods under correct config switch --- Antigen/Helpers/VectorHelpers.cs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index 7dd5ecf..9442c62 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -98,7 +98,18 @@ private void GenerateVectorMethods() { RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); } + } + if (PRNG.Decide(TC.Config.AvxMethodsProbability)) + { + if (Avx.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx)); + } + if (Avx2.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx2)); + } if (Avx512BW.IsSupported) { RecordIntrinsicMethods(typeof(Avx512BW)); @@ -125,18 +136,6 @@ private void GenerateVectorMethods() } } - if (PRNG.Decide(TC.Config.AvxMethodsProbability)) - { - if (Avx.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx)); - } - if (Avx2.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx2)); - } - } - if (PRNG.Decide(TC.Config.SSEMethodsProbability)) { if (Sse.IsSupported) From a687441b1708c2604feaa4483ce80aeb00715d58 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 31 Aug 2023 19:44:50 -0700 Subject: [PATCH 114/149] Skip Unsafe methods --- Antigen/Helpers/VectorHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index 9442c62..3f28537 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -219,7 +219,7 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || fullMethodName.Contains("Vector`1") || fullMethodName.Contains("Divide") || - fullMethodName.Contains("FloatComparisonMode")) + fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("Unsafe")) { // We do not support these types, so ignore these methods. continue; From ad62b45e4440a89e34287472da41c75952dd8f3c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 2 Sep 2023 07:19:07 -0700 Subject: [PATCH 115/149] Replace COMPlus_ -> DOTNET_ --- Antigen/Config/EnvVarOptions.cs | 50 ++++++++++++++++----------------- Antigen/Config/RunOptions.cs | 4 +-- Trimmer/TestTrimmer.cs | 4 +-- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index 088ca07..15521f7 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -10,25 +10,25 @@ namespace Antigen.Config { public static class EnvVarOptions { - private static List s_baselineGroups; - private static readonly List> s_baselineGroupWeight = new(); + private static List s_baselineGroups; + private static readonly List> s_baselineGroupWeight = new(); - private static List s_testGroups; - private static readonly List> s_testGroupWeight = new(); + private static List s_testGroups; + private static readonly List> s_testGroupWeight = new(); - internal static void Initialize(List baselineEnvVars, List testEnvVars) + internal static void Initialize(List baselineEnvVars, List testEnvVars) { s_baselineGroups = baselineEnvVars; foreach (var base_group in s_baselineGroups) { - s_baselineGroupWeight.Add(new Weights(base_group, base_group.Weight)); + s_baselineGroupWeight.Add(new Weights(base_group, base_group.Weight)); base_group.PopulateWeights(); } s_testGroups = testEnvVars; foreach (var test_group in s_testGroups) { - s_testGroupWeight.Add(new Weights(test_group, test_group.Weight)); + s_testGroupWeight.Add(new Weights(test_group, test_group.Weight)); test_group.PopulateWeights(); } } @@ -37,7 +37,7 @@ internal static void Initialize(List baselineEnvVars, List /// - private static ComplusEnvVarGroup GetRandomOsrTestGroup() + private static DotnetEnvVarGroup GetRandomOsrTestGroup() { return PRNG.WeightedChoice(s_testGroupWeight.Where(tg => tg.Data.IsOsrSwitchGroup())); } @@ -46,7 +46,7 @@ private static ComplusEnvVarGroup GetRandomOsrTestGroup() /// Returns a random EnvVarGroup depending on the weight. /// /// - private static ComplusEnvVarGroup GetRandomNonOsrTestGroup() + private static DotnetEnvVarGroup GetRandomNonOsrTestGroup() { return PRNG.WeightedChoice(s_testGroupWeight.Where(tg => !tg.Data.IsOsrSwitchGroup())); } @@ -62,7 +62,7 @@ public static Dictionary BaseLineVars() { foreach (var variable in group.Variables) { - envVars[$"COMPlus_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; + envVars[$"DOTNET_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; } } return envVars; @@ -83,7 +83,7 @@ public static Dictionary TestVars(bool includeOsrSwitches) var defaultVariablesCount = PRNG.Next(1, 8); for (var i = 0; i < defaultVariablesCount; i++) { - ComplusEnvVar envVar; + DotnetEnvVar envVar; // Avoid duplicate variables do @@ -91,7 +91,7 @@ public static Dictionary TestVars(bool includeOsrSwitches) envVar = defaultGroup.GetRandomVariable(); } while (!usedEnvVars.Add(envVar.Name)); - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + envVars[$"DOTNET_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; } // OSR switches @@ -102,19 +102,19 @@ public static Dictionary TestVars(bool includeOsrSwitches) foreach (var osrSwitch in osrstressGroup.Variables) { Debug.Assert(osrSwitch.Values.Length == 1); - envVars[$"COMPlus_{osrSwitch.Name}"] = osrSwitch.Values[0]; + envVars[$"DOTNET_{osrSwitch.Name}"] = osrSwitch.Values[0]; } } else { - envVars["COMPlus_TieredCompilation"] = "0"; + envVars["DOTNET_TieredCompilation"] = "0"; } // stress switches var stressVariablesCount = PRNG.Next(1, 4); for (var i = 0; i < stressVariablesCount; i++) { - ComplusEnvVar envVar; + DotnetEnvVar envVar; // Avoid duplicate variables do @@ -123,14 +123,14 @@ public static Dictionary TestVars(bool includeOsrSwitches) envVar = stressGroup.GetRandomVariable(); } while (!usedEnvVars.Add(envVar.Name)); - envVars[$"COMPlus_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; + envVars[$"DOTNET_{envVar.Name}"] = envVar.Values[PRNG.Next(envVar.Values.Length)]; } return envVars; } } - public class ComplusEnvVar + public class DotnetEnvVar { public string Name; public string[] Values; @@ -138,12 +138,12 @@ public class ComplusEnvVar public override string ToString() { - return $"COMPlus_{Name}=[{string.Join(",", Values)}]"; + return $"DOTNET_{Name}=[{string.Join(",", Values)}]"; } public override bool Equals(object obj) { - if (obj is not ComplusEnvVar otherObj) + if (obj is not DotnetEnvVar otherObj) { return false; } @@ -157,16 +157,16 @@ public override int GetHashCode() } } - public class ComplusEnvVarGroup + public class DotnetEnvVarGroup { public string Name; public double Weight; - public List Variables; + public List Variables; /// /// Weights of individual EnvVars present in this group. /// - private readonly List> _variableWeights = new List>(); + private readonly List> _variableWeights = new List>(); /// /// Populate list of weighted choices. @@ -176,12 +176,12 @@ internal void PopulateWeights() Variables.ForEach(v => AddVariable(v)); } - private void AddVariable(ComplusEnvVar variable) + private void AddVariable(DotnetEnvVar variable) { - _variableWeights.Add(new Weights(variable, variable.Weight)); + _variableWeights.Add(new Weights(variable, variable.Weight)); } - public ComplusEnvVar GetRandomVariable() + public DotnetEnvVar GetRandomVariable() { return PRNG.WeightedChoice(_variableWeights); } diff --git a/Antigen/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs index a74a1ca..e12b89f 100644 --- a/Antigen/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -30,9 +30,9 @@ public class RunOptions public List Configs; - public List BaselineEnvVars; + public List BaselineEnvVars; - public List TestEnvVars; + public List TestEnvVars; /// /// If this run supports Vector64. diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 75da95a..a7b1129 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -85,12 +85,12 @@ private void ParseEnvironment() if (!string.IsNullOrEmpty(_opts.AltJitName)) { - _testVariables["COMPlus_AltJitName"] = _opts.AltJitName; + _testVariables["DOTNET_AltJitName"] = _opts.AltJitName; } if (!string.IsNullOrEmpty(_opts.AltJitMethodName)) { - _testVariables["COMPlus_AltJit"] = _opts.AltJitMethodName; + _testVariables["DOTNET_AltJit"] = _opts.AltJitMethodName; } return; } From a540c90a84b7b28c3d93164a2a425ebc7cb7f34a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 6 Sep 2023 00:08:58 -0700 Subject: [PATCH 116/149] Update restore packages --- Antigen/Antigen.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index f88f9a1..ceafcd6 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -25,6 +25,9 @@ false + + https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json + From 90e68767fe8ed064cf6690dbe519abd215d5ebc9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 8 Sep 2023 07:48:57 -0700 Subject: [PATCH 117/149] Add DOTNET_PreferredVectorBitWidth to Antigen --- Antigen/Config/EnvVarOptions.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index 15521f7..336db19 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; namespace Antigen.Config { @@ -16,6 +17,8 @@ public static class EnvVarOptions private static List s_testGroups; private static readonly List> s_testGroupWeight = new(); + private static bool s_IsArm = (RuntimeInformation.OSArchitecture == Architecture.Arm) || (RuntimeInformation.OSArchitecture == Architecture.Arm64); + internal static void Initialize(List baselineEnvVars, List testEnvVars) { s_baselineGroups = baselineEnvVars; @@ -108,6 +111,10 @@ public static Dictionary TestVars(bool includeOsrSwitches) else { envVars["DOTNET_TieredCompilation"] = "0"; + if (!s_IsArm) + { + envVars["DOTNET_PreferredVectorBitWidth"] = "512"; + } } // stress switches From 219c5bef64ef809dce1da159d1df50fcf7068bd8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 2 Apr 2024 13:05:45 -0700 Subject: [PATCH 118/149] Reenable OptRepeat --- Antigen/Config/antigen.json | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index 0d143ab..e992f2b 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -345,22 +345,25 @@ "1" ] }, - //{ - // "Name": "JitOptRepeat", - // "Weight": 0.0005, - // "Values": [ - // "*" - // ] - //}, - //{ - // "Name": "JitOptRepeatCount", - // "Weight": 0.0003, - // "Values": [ - // "1", - // "2", - // "5" - // ] - //}, + { + "Name": "JitOptRepeat", + "Weight": 0.0005, + "Values": [ + "*" + ] + }, + { + "Name": "JitOptRepeatCount", + "Weight": 0.0003, + "Values": [ + "2", + "3", + "4", + "5", + "6", + "10" + ] + }, { "Name": "TailCallLoopOpt", "Weight": 0.03, From b9c6d4ea1643d40ceab7dbdc541f0c18b3cba1ac Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 2 Aug 2024 06:52:20 -0700 Subject: [PATCH 119/149] Sve (#5) * Working Vector and SVE fix a bug for unique issue * Set altjit for x64 * Use Sve for xarch * Update the config name * wip: * work for x64 and arm64 * some minor cleanup * minor comment removal --------- Co-authored-by: Kunal Pathak --- Antigen/Antigen.csproj | 3 +- Antigen/Config/ConfigOptions.cs | 21 +- Antigen/Config/EnvVarOptions.cs | 42 +++- Antigen/Config/antigen.json | 2 +- Antigen/Expressions/ConstantValue.cs | 3 + Antigen/Helpers/PreGenerated.cs | 4 +- Antigen/Helpers/VectorHelpers.cs | 292 +++++++++++++++------------ Antigen/TestCase.cs | 40 +++- Antigen/TestClass.cs | 6 +- Antigen/TestMethod.cs | 12 +- Antigen/Tree/Types.cs | 67 +++++- 11 files changed, 337 insertions(+), 155 deletions(-) diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index ceafcd6..8d776b4 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -2,9 +2,10 @@ Exe - net8.0 + net9.0 Antigen ab71806a-3bd8-4fb1-b0e2-9450aec41a9f + True diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index d857b0b..b391817 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -11,12 +11,14 @@ public class ConfigOptions public string Name; + public bool UseSve; + // Test general configuration public int MaxStmtDepth = 4; public int MaxExprDepth = 3; public int MethodCount = 3; - public int MaxStatementCount = 7; + public int MaxStatementCount = 2; public int VariablesCount = 8; public int StructCount = 2; @@ -56,6 +58,7 @@ public class ConfigOptions public double UShortWeight = 0.4; public double UIntWeight = 0.45; public double ULongWeight = 0.6; + public double SveMaskPatternWeight = 0; // Vector weights public double Vector64_ByteWeight = 0.1; @@ -102,6 +105,17 @@ public class ConfigOptions public double Vector512_FloatWeight = 0.15; public double Vector512_DoubleWeight = 0.15; + public double Vector_ByteWeight = 0.15; + public double Vector_SByteWeight = 0.15; + public double Vector_ShortWeight = 0.15; + public double Vector_UShortWeight = 0.15; + public double Vector_IntWeight = 0.15; + public double Vector_UIntWeight = 0.15; + public double Vector_LongWeight = 0.15; + public double Vector_ULongWeight = 0.15; + public double Vector_FloatWeight = 0.15; + public double Vector_DoubleWeight = 0.15; + public double Vector2Weight = 0.1; public double Vector3Weight = 0.1; public double Vector4Weight = 0.1; @@ -296,6 +310,11 @@ public class ConfigOptions /// public double AdvSimdMethodsProbability = 0.35; + /// + /// AdvSimd methods probability + /// + public double SveMethodsProbability = 1; + /// /// Probability in which vector methods will be included. /// diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index 336db19..a5ff2bb 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -58,7 +58,7 @@ private static DotnetEnvVarGroup GetRandomNonOsrTestGroup() /// Returns random set of baseline environment variables. /// /// - public static Dictionary BaseLineVars() + public static Dictionary BaseLineVars(bool useSve) { var envVars = new Dictionary(); foreach (var group in s_baselineGroups) @@ -68,6 +68,11 @@ public static Dictionary BaseLineVars() envVars[$"DOTNET_{variable.Name}"] = variable.Values[PRNG.Next(variable.Values.Length)]; } } + + if (useSve) + { + AddSveSwitches(ref envVars); + } return envVars; } @@ -75,7 +80,7 @@ public static Dictionary BaseLineVars() /// Returns random set of test environment variables. /// /// - public static Dictionary TestVars(bool includeOsrSwitches) + public static Dictionary TestVars(bool includeOsrSwitches, bool useSve) { var envVars = new Dictionary(); @@ -111,7 +116,15 @@ public static Dictionary TestVars(bool includeOsrSwitches) else { envVars["DOTNET_TieredCompilation"] = "0"; - if (!s_IsArm) + if (s_IsArm) + { + envVars["DOTNET_MaxVectorTBitWidth"] = "128"; + } + else if (useSve) + { + AddSveSwitches(ref envVars); + } + else { envVars["DOTNET_PreferredVectorBitWidth"] = "512"; } @@ -135,6 +148,29 @@ public static Dictionary TestVars(bool includeOsrSwitches) return envVars; } + + private static void AddSveSwitches(ref Dictionary envVars) + { + string altjitName = "clrjit_universal_arm64_x64"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + altjitName += ".dylib"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + altjitName += ".so"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + altjitName += ".dll"; + } + + envVars["DOTNET_AltJitName"] = altjitName; + envVars["DOTNET_AltJit"] = "*"; + envVars["DOTNET_MaxVectorTBitWidth"] = "128"; + } } public class DotnetEnvVar diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index e992f2b..a964f1b 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -888,7 +888,7 @@ "MaxExprDepth": 5, "VariablesCount": 10, "MethodCount": 5, - "MaxStatementCount": 10, + "MaxStatementCount": 3, "TryCatchFinallyStatementWeight": 0.03, "LocalVariablesLogProbability": 1.0 }, diff --git a/Antigen/Expressions/ConstantValue.cs b/Antigen/Expressions/ConstantValue.cs index eae5ede..2a3e09b 100644 --- a/Antigen/Expressions/ConstantValue.cs +++ b/Antigen/Expressions/ConstantValue.cs @@ -141,6 +141,9 @@ public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList(); + s_allVectorMethods = new List(); + RecordIntrinsicMethods(typeof(Vector)); RecordIntrinsicMethods(typeof(Vector2)); RecordIntrinsicMethods(typeof(Vector3)); RecordIntrinsicMethods(typeof(Vector4)); @@ -34,7 +35,7 @@ private void GenerateVectorMethods() RecordVectorCtors(typeof(Vector3)); RecordVectorCtors(typeof(Vector4)); - if (Program.s_runOptions.SupportsVector64) + if (TC.Config.UseSve || Program.s_runOptions.SupportsVector64) { RecordIntrinsicMethods(typeof(Vector64)); } @@ -50,143 +51,172 @@ private void GenerateVectorMethods() { RecordIntrinsicMethods(typeof(Vector512)); } - - if (PRNG.Decide(TC.Config.TraditionalMethodsProbability)) + if (System.Runtime.Intrinsics.X86.Aes.IsSupported) { - if (System.Runtime.Intrinsics.X86.Aes.IsSupported) - { - RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); - } - - if (Bmi1.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi1)); - } - if (Bmi1.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); - } - if (Bmi2.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi2)); - } - if (Bmi2.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); - } - if (Fma.IsSupported) - { - RecordIntrinsicMethods(typeof(Fma)); - } - if (Lzcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt)); - } - if (Lzcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); - } - if (Pclmulqdq.IsSupported) - { - RecordIntrinsicMethods(typeof(Pclmulqdq)); - } - if (Popcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt)); - } - if (Popcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); - } + RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); } - - if (PRNG.Decide(TC.Config.AvxMethodsProbability)) + if (Bmi1.IsSupported) { - if (Avx.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx)); - } - if (Avx2.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx2)); - } - if (Avx512BW.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512BW)); - } - - if (Avx512CD.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512CD)); - } - - if (Avx512DQ.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512DQ)); - } - - if (Avx512F.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512F)); - } - - if (Avx512Vbmi.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512Vbmi)); - } + RecordIntrinsicMethods(typeof(Bmi1)); } - - if (PRNG.Decide(TC.Config.SSEMethodsProbability)) + if (Bmi1.X64.IsSupported) { - if (Sse.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse)); - } - if (Sse2.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse2)); - } - if (Sse3.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse3)); - } - if (Sse41.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse41)); - } - if (Sse42.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse42)); - } - if (Ssse3.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse)); - } + RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); } - - if (PRNG.Decide(TC.Config.AdvSimdMethodsProbability)) + if (Bmi2.IsSupported) { - if (AdvSimd.IsSupported) - { - RecordIntrinsicMethods(typeof(AdvSimd)); - } - - if (AdvSimd.Arm64.IsSupported) - { - RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); - } + RecordIntrinsicMethods(typeof(Bmi2)); + } + if (Bmi2.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + } + if (Fma.IsSupported) + { + RecordIntrinsicMethods(typeof(Fma)); + } + if (Lzcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt)); + } + if (Lzcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); + } + if (Pclmulqdq.IsSupported) + { + RecordIntrinsicMethods(typeof(Pclmulqdq)); + } + if (Popcnt.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt)); + } + if (Popcnt.X64.IsSupported) + { + RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + } + if (Avx.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx)); + } + if (Avx2.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx2)); + } + if (Avx512BW.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512BW)); + } + if (Avx512CD.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512CD)); + } + if (Avx512DQ.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512DQ)); + } + if (Avx512F.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512F)); + } + if (Avx512Vbmi.IsSupported) + { + RecordIntrinsicMethods(typeof(Avx512Vbmi)); + } + if (Sse.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } + if (Sse2.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse2)); + } + if (Sse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse3)); + } + if (Sse41.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse41)); + } + if (Sse42.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse42)); + } + if (Ssse3.IsSupported) + { + RecordIntrinsicMethods(typeof(Sse)); + } + if (AdvSimd.IsSupported || TC.Config.UseSve) + { + RecordIntrinsicMethods(typeof(AdvSimd)); + } + if (AdvSimd.Arm64.IsSupported || TC.Config.UseSve) + { + RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + } + if (Sve.IsSupported || TC.Config.UseSve) + { + RecordIntrinsicMethods(typeof(Sve)); } - isVectorMethodsInitialized = true; } } - foreach (var vectorMethod in vectorMethods) + bool addAvx = PRNG.Decide(TC.Config.AvxMethodsProbability); + bool addSse = PRNG.Decide(TC.Config.SSEMethodsProbability); + bool addTraditional = PRNG.Decide(TC.Config.TraditionalMethodsProbability); + bool addSve = TC.Config.UseSve || PRNG.Decide(TC.Config.SveMethodsProbability); + bool addAdvsimd = TC.Config.UseSve || PRNG.Decide(TC.Config.AdvSimdMethodsProbability); + + // Register all the vector create methods + foreach (var vectorMethod in s_allVectorMethods) { - if (PRNG.Decide(TC.Config.RegisterIntrinsicMethodsProbability) || vectorMethod.IsVectorCreateMethod) + if (vectorMethod.IsVectorCreateMethod) { - // Add all vector create methods RegisterMethod(vectorMethod); + continue; + } + bool isSve = vectorMethod.MethodName.StartsWith("Sve."); + bool isAdvSimd = vectorMethod.MethodName.StartsWith("AdvSimd."); + bool isAvx = vectorMethod.MethodName.StartsWith("Avx"); + bool isSse = vectorMethod.MethodName.StartsWith("Sse"); + bool isTraditional = vectorMethod.MethodName.StartsWith("Bmi") || + vectorMethod.MethodName.StartsWith("Fma") || + vectorMethod.MethodName.StartsWith("Lzcnt") || + vectorMethod.MethodName.StartsWith("Pclmulqdq") || + vectorMethod.MethodName.StartsWith("Popcnt"); + + if (TC.Config.UseSve) + { + // If force-sve, then just add Sve/AdvSimd methods + if (isSve || isAdvSimd) + { + RegisterMethod(vectorMethod); + } + } + else + { + if (addAdvsimd && isAdvSimd) + { + RegisterMethod(vectorMethod); + } + if (addSve && isSve) + { + RegisterMethod(vectorMethod); + } + if (addAvx && isAvx) + { + RegisterMethod(vectorMethod); + } + if (addSse && isSse) + { + RegisterMethod(vectorMethod); + } + if (addTraditional && isTraditional) + { + RegisterMethod(vectorMethod); + } } } } @@ -218,13 +248,19 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam fullMethodName.Contains("Matrix") || fullMethodName.Contains("Span") || fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || - fullMethodName.Contains("Vector`1") || fullMethodName.Contains("Divide") || + fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") || + fullMethodName.Contains("SveMaskPattern") || fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("Unsafe")) { // We do not support these types, so ignore these methods. continue; } + if (fullMethodName.Contains("SveMaskPattern")) + { + Console.WriteLine(""); + } + string vectorsInMethod = Tree.ValueType.GetVectorList(fullMethodName); // If a parameter is one of the vector that is not supported, then skip this method @@ -244,13 +280,13 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam foreach (var genericArgument in s_vectorGenericArgs) { var genericInitVectorMethod = method.MakeGenericMethod(genericArgument); - vectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod)); + s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod)); } } } else { - vectorMethods.Add(CreateMethodSignature(vectorTypeName, method)); + s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, method)); } } } @@ -328,7 +364,7 @@ private static void RecordVectorCtors(Type vectorType) }); } - vectorMethods.Add(ms); + s_allVectorMethods.Add(ms); } } diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index c8bb627..6ef89f5 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -5,9 +5,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.IO; using System.Linq; using System.Text; +using System.Threading; using Utils; namespace Antigen @@ -79,6 +81,21 @@ public TestCase(int testId, RunOptions runOptions) Config = s_runOptions.Configs[PRNG.Next(s_runOptions.Configs.Count)]; ContainsVectorData = PRNG.Decide(Config.VectorDataProbability); + if (RuntimeInformation.OSArchitecture == Architecture.X64) + { + if (PRNG.Decide(Config.SveMethodsProbability)) + { + Config.UseSve = true; + ContainsVectorData = true; + } + } + else + { + // local temporary change + Config.UseSve = true; + ContainsVectorData = true; + } + AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; s_testRunner = TestRunner.GetInstance(s_runOptions.CoreRun, s_runOptions.OutputDirectory); @@ -105,7 +122,7 @@ public TestResult Verify() //fileContents.AppendLine($"Got {compileResult.CompileErrors.Count()} compiler error(s):"); //foreach (var error in compileResult.CompileErrors) //{ - // fileContents.AppendLine(error.ToString()); + // fileContents.AppendLine(error.ToString()); //} //fileContents.AppendLine("*/"); @@ -120,8 +137,9 @@ public TestResult Verify() File.WriteAllText(workingFile, testCaseRoot.ToFullString()); } #endif - var baselineVariables = EnvVarOptions.BaseLineVars(); - var testVariables = EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3)); + bool isx64 = RuntimeInformation.OSArchitecture == Architecture.X64; + var baselineVariables = EnvVarOptions.BaseLineVars(Config.UseSve && isx64); + var testVariables = EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), Config.UseSve && isx64); // Execute test first and see if we have any errors/asserts var test = s_testRunner.Execute(compileResult, testVariables); @@ -296,13 +314,19 @@ private void SaveTestCase( string currentReproFile = $"{testFileName}.g.cs"; lock (Program.s_spinLock) { + UniqueIssueFile uniqueIssueFile; if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { - s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile); + uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile); + } + else + { + uniqueIssueFile = s_uniqueIssues[assertionHashCode]; } // Create hash of testAssertion and copy files in respective bucket. - uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{s_uniqueIssues[assertionHashCode].UniqueIssueId}"); + uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{uniqueIssueFile.UniqueIssueId}"); + if (!Directory.Exists(uniqueIssueDirName)) { Directory.CreateDirectory(uniqueIssueDirName); @@ -310,9 +334,9 @@ private void SaveTestCase( } // Only cache 1 file of smallest possible size. - if (s_uniqueIssues[assertionHashCode].FileSize > fileContents.Length) + if (uniqueIssueFile.FileSize > fileContents.Length) { - string largerReproFile = Path.Combine(uniqueIssueDirName, s_uniqueIssues[assertionHashCode].FileName); + string largerReproFile = Path.Combine(uniqueIssueDirName, uniqueIssueFile.FileName); if (File.Exists(largerReproFile)) { File.Delete(largerReproFile); @@ -324,7 +348,7 @@ private void SaveTestCase( File.WriteAllText(failFile, fileContents.ToString()); // Update the file size - s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(s_uniqueIssues.Count, fileContents.Length, currentReproFile); + s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(uniqueIssueFile.UniqueIssueId, fileContents.Length, currentReproFile); } } } diff --git a/Antigen/TestClass.cs b/Antigen/TestClass.cs index 9a3009a..7bce59b 100644 --- a/Antigen/TestClass.cs +++ b/Antigen/TestClass.cs @@ -28,7 +28,7 @@ public partial class TestClass public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } private List> _methods { get; set; } - private static List vectorMethods = null; + private static List s_allVectorMethods = null; private static bool isVectorMethodsInitialized = false; private int _variableId; @@ -124,9 +124,9 @@ public MethodSignature GetRandomVectorCreateMethod(Tree.ValueType returnType) /// public MethodSignature GetRandomVectorMethod(Tree.ValueType returnType) { - var matchingMethods = AllVectorMethods.Where(m => m.Data.ReturnType.Equals(returnType)).ToList(); + var matchingMethods = AllVectorMethods.Where(m => m.Data.ReturnType.Equals(returnType)); - if (matchingMethods.Count == 0) + if (matchingMethods.Count() == 0) { return null; } diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index aa7d06b..520f8bf 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -2,6 +2,7 @@ using Antigen.Statements; using Antigen.Tree; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; @@ -868,7 +869,11 @@ private Expression MethodCallHelper(MethodSignature methodSig, int depth) Tree.ValueType argType = parameter.ParamType; ExprKind argExprKind; - + // if (argType.PrimitiveType == Primitive.SveMaskPattern) + // { + // argExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, argType); + // } + // else if (parameter.PassingWay == ParamValuePassing.None) { if (depth < TC.Config.MaxExprDepth) @@ -912,6 +917,11 @@ private Expression MethodCallHelper(MethodSignature methodSig, int depth) } } + // if (argType.PrimitiveType == Primitive.SveMaskPattern) + // { + // argExpr = new CastExpression(TC, argExpr, argType); + // } + passingWays.Add(parameter.PassingWay); argumentNodes.Add(argExpr); } diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index 70b4ea3..35c7491 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -32,7 +32,9 @@ public enum Primitive : ulong String = 0x2000, Struct = 0x4000, - Numeric = Byte | SByte | Short | UShort | Int | UInt | Long | ULong | Float | Double | Decimal, + // SveMaskPattern = 0x8000, + + Numeric = Byte | SByte | Short | UShort | Int | UInt | Long | ULong | Float | Double | Decimal /*| SveMaskPattern*/, SignedInteger = SByte | Short | Int | Long, UnsignedInteger = Byte | UShort | UInt | ULong, Integer = SignedInteger | UnsignedInteger, @@ -86,9 +88,19 @@ public enum VectorType : ulong Vector512_Float = 39, Vector512_Double = 40, - Vector2 = 41, - Vector3 = 42, - Vector4 = 43, + Vector_Byte = 41, + Vector_SByte = 42, + Vector_Short = 43, + Vector_UShort = 44, + Vector_Int = 45, + Vector_UInt = 46, + Vector_Long = 47, + Vector_ULong = 48, + Vector_Float = 49, + Vector_Double = 50, + Vector2 = 51, + Vector3 = 52, + Vector4 = 53, } public struct ValueType @@ -110,7 +122,7 @@ public bool IsVectorIntrinsics() { if (IsVectorType) { - if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector512_Double) + if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector_Double) { return true; } @@ -184,6 +196,7 @@ private ValueType(VectorType vectorType, string displayText, string variableName new ValueType(Primitive.UShort, "ushort", SyntaxKind.UShortKeyword), new ValueType(Primitive.UInt, "uint", SyntaxKind.UIntKeyword), new ValueType(Primitive.ULong, "ulong", SyntaxKind.ULongKeyword), + // new ValueType(Primitive.SveMaskPattern, "SveMaskPattern", SyntaxKind.EnumKeyword), }; private static readonly List s_vectorTypes = new(); @@ -246,12 +259,24 @@ static ValueType() s_vectorTypes.Add(new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double")); } + + s_vectorTypes.Add(new ValueType(VectorType.Vector_Byte, "Vector", "v_byte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_SByte, "Vector", "v_sbyte")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_Short, "Vector", "v_short")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_UShort, "Vector", "v_ushort")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_Int, "Vector", "v_int")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_UInt, "Vector", "v_uint")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_Long, "Vector", "v_long")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_ULong, "Vector", "v_ulong")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_Float, "Vector", "v_float")); + s_vectorTypes.Add(new ValueType(VectorType.Vector_Double, "Vector", "v_double")); + s_vectorTypes.Add(new ValueType(VectorType.Vector2, "Vector2", "v2")); s_vectorTypes.Add(new ValueType(VectorType.Vector3, "Vector3", "v3")); s_vectorTypes.Add(new ValueType(VectorType.Vector4, "Vector4", "v4")); } - private static readonly Regex vectorRegex = new Regex(@"Vector(64|128|256|512)`1\[(.*)\]"); + private static readonly Regex vectorRegex = new Regex(@"Vector(64|128|256|512)?`1\[(.*)\]"); private static readonly Regex multipleVectorsRegex = new Regex(@"Vector(64|128|256|512)`1"); /// @@ -261,7 +286,6 @@ static ValueType() /// public static string GetVectorList(string typeName) { - var vectorTypeMatches = multipleVectorsRegex.Matches(typeName); if (vectorTypeMatches.Count == 0) { @@ -290,6 +314,20 @@ public static ValueType ParseType(string typeName) parsedVectorType = vectorLength switch { + "" => templateParameterType switch + { + "System.Byte" => VectorType.Vector_Byte, + "System.SByte" => VectorType.Vector_SByte, + "System.Int16" => VectorType.Vector_Short, + "System.UInt16" => VectorType.Vector_UShort, + "System.Int32" => VectorType.Vector_Int, + "System.UInt32" => VectorType.Vector_UInt, + "System.Int64" => VectorType.Vector_Long, + "System.UInt64" => VectorType.Vector_ULong, + "System.Single" => VectorType.Vector_Float, + "System.Double" => VectorType.Vector_Double, + _ => throw new Exception("Invalid template parameter for Vector"), + }, "64" => templateParameterType switch { "System.Byte" => VectorType.Vector64_Byte, @@ -361,6 +399,10 @@ public static ValueType ParseType(string typeName) }; return s_vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); } + // else if (typeName == "System.Runtime.Intrinsics.Arm.SveMaskPattern") + // { + // return types.FirstOrDefault(t => t.PrimitiveType == Primitive.SveMaskPattern); + // } else { var parsedPrimitiveType = typeName switch @@ -392,6 +434,17 @@ public static int GetElementCount(VectorType vectorType) { switch (vectorType) { + case VectorType.Vector_Byte: return Vector.Count; + case VectorType.Vector_SByte: return Vector.Count; + case VectorType.Vector_Short: return Vector.Count; + case VectorType.Vector_UShort: return Vector.Count; + case VectorType.Vector_Int: return Vector.Count; + case VectorType.Vector_UInt: return Vector.Count; + case VectorType.Vector_Long: return Vector.Count; + case VectorType.Vector_ULong: return Vector.Count; + case VectorType.Vector_Float: return Vector.Count; + case VectorType.Vector_Double: return Vector.Count; + case VectorType.Vector64_Byte: return Vector64.Count; case VectorType.Vector64_SByte: return Vector64.Count; case VectorType.Vector64_Short: return Vector64.Count; From 75035187020c217818627c46e1d1cde6d9ec1a87 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 2 Aug 2024 20:55:05 -0700 Subject: [PATCH 120/149] No sve for arm64 --- Antigen/Antigen.cs | 7 ++++++- Antigen/Config/EnvVarOptions.cs | 4 ++++ Antigen/TestCase.cs | 12 ++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 5d0ef71..6c6b2df 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -171,10 +171,15 @@ static void RunTest() var currTestId = GetNextTestId(); var testCase = new TestCase(currTestId, s_runOptions); testCase.Generate(); + string configName = testCase.Config.Name; + if (testCase.ContainsVectorData) + { + configName += " (vector)"; + } var result = testCase.Verify(); Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", currTestId, - testCase.Config.Name, + configName, Enum.GetName(typeof(TestResult), result), (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, (DateTime.Now - s_startTime).ToString()); diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index a5ff2bb..5058346 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -69,6 +69,10 @@ public static Dictionary BaseLineVars(bool useSve) } } + if (s_IsArm) + { + envVars["DOTNET_MaxVectorTBitWidth"] = "128"; + } if (useSve) { AddSveSwitches(ref envVars); diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 6ef89f5..a3b9dbc 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -89,12 +89,12 @@ public TestCase(int testId, RunOptions runOptions) ContainsVectorData = true; } } - else - { - // local temporary change - Config.UseSve = true; - ContainsVectorData = true; - } + // else + // { + // // local temporary change + // Config.UseSve = true; + // ContainsVectorData = true; + // } AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; From 5977e8ea2b0b9aab2da88a76c56647023844a89e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 4 Aug 2024 01:17:50 -0700 Subject: [PATCH 121/149] print typename error --- Antigen/Config/EnvVarOptions.cs | 3 +++ Antigen/Tree/Types.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Antigen/Config/EnvVarOptions.cs b/Antigen/Config/EnvVarOptions.cs index 5058346..96cba91 100644 --- a/Antigen/Config/EnvVarOptions.cs +++ b/Antigen/Config/EnvVarOptions.cs @@ -123,6 +123,8 @@ public static Dictionary TestVars(bool includeOsrSwitches, bool if (s_IsArm) { envVars["DOTNET_MaxVectorTBitWidth"] = "128"; + envVars["DOTNET_PreferredVectorBitWidth"] = "0"; + } else if (useSve) { @@ -174,6 +176,7 @@ private static void AddSveSwitches(ref Dictionary envVars) envVars["DOTNET_AltJitName"] = altjitName; envVars["DOTNET_AltJit"] = "*"; envVars["DOTNET_MaxVectorTBitWidth"] = "128"; + envVars["DOTNET_PreferredVectorBitWidth"] = "0"; } } diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index 35c7491..ffa91a0 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -419,7 +419,7 @@ public static ValueType ParseType(string typeName) "System.UInt64" => Primitive.ULong, "System.Single" => Primitive.Float, "System.Double" => Primitive.Double, - _ => throw new Exception("Invalid typename parameter"), + _ => throw new Exception($"Invalid typename parameter - '{typeName}'"), }; return types.FirstOrDefault(t => t.PrimitiveType == parsedPrimitiveType); } From 2765b09242f9db585ee9f13b61756bc1c714f20c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 4 Aug 2024 07:09:12 -0700 Subject: [PATCH 122/149] ignore FloatRoundingMode and SvePrefetchType --- Antigen/Helpers/VectorHelpers.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index 259ccc8..82ac87d 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -249,18 +249,14 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") || - fullMethodName.Contains("SveMaskPattern") || - fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("Unsafe")) + fullMethodName.Contains("SveMaskPattern") || fullMethodName.Contains("SvePrefetchType") || + fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("FloatRoundingMode") || + fullMethodName.Contains("Unsafe")) { // We do not support these types, so ignore these methods. continue; } - if (fullMethodName.Contains("SveMaskPattern")) - { - Console.WriteLine(""); - } - string vectorsInMethod = Tree.ValueType.GetVectorList(fullMethodName); // If a parameter is one of the vector that is not supported, then skip this method From 337cc18690c706e422124d529b2ab3ad89e843d4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 5 Aug 2024 21:10:29 -0700 Subject: [PATCH 123/149] various bug fixes and SveMaskPattern --- Antigen/Antigen.cs | 9 +- Antigen/Config/ConfigOptions.cs | 2 +- Antigen/Config/RunOptions.cs | 26 -- Antigen/Expressions/ConstantValue.cs | 3 + Antigen/Helpers/Literals.cs | 21 +- Antigen/Helpers/VectorHelpers.cs | 422 ++++++++++++++------------- Antigen/TestClass.cs | 143 ++++++++- Antigen/TestMethod.cs | 13 +- Antigen/Tree/AstUtils.cs | 2 +- Antigen/Tree/Scope.cs | 3 +- Antigen/Tree/Types.cs | 185 +++++------- 11 files changed, 469 insertions(+), 360 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 6c6b2df..a08bf6d 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -165,6 +165,9 @@ static void RunTest() { TestResult.OOM, 0 }, }; + // Generate vector methods + VectorHelpers.RecordVectorMethods(); + int testCount = 0; while (!Done) { @@ -174,7 +177,11 @@ static void RunTest() string configName = testCase.Config.Name; if (testCase.ContainsVectorData) { - configName += " (vector)"; + configName += " (Vector)"; + } + if (testCase.Config.UseSve) + { + configName += " (SVE)"; } var result = testCase.Verify(); Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index b391817..e55df06 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -313,7 +313,7 @@ public class ConfigOptions /// /// AdvSimd methods probability /// - public double SveMethodsProbability = 1; + public double SveMethodsProbability = 0.5; /// /// Probability in which vector methods will be included. diff --git a/Antigen/Config/RunOptions.cs b/Antigen/Config/RunOptions.cs index e12b89f..537bad2 100644 --- a/Antigen/Config/RunOptions.cs +++ b/Antigen/Config/RunOptions.cs @@ -34,27 +34,6 @@ public class RunOptions public List TestEnvVars; - /// - /// If this run supports Vector64. - /// - public bool SupportsVector64 { get; private set; } - - /// - /// If this run supports Vector128. - /// - public bool SupportsVector128 { get; private set; } - - /// - /// If this run supports Vector256. - /// - public bool SupportsVector256 { get; private set; } - - /// - /// If this run supports Vector512. - /// - public bool SupportsVector512 { get; private set; } - - internal static RunOptions Initialize() { string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -64,11 +43,6 @@ internal static RunOptions Initialize() var runOption = JsonConvert.DeserializeObject(File.ReadAllText(antiGenConfig)); EnvVarOptions.Initialize(runOption.BaselineEnvVars, runOption.TestEnvVars); - runOption.SupportsVector64 = Vector64.IsHardwareAccelerated; - runOption.SupportsVector128 = Vector128.IsHardwareAccelerated; - runOption.SupportsVector256 = Vector256.IsHardwareAccelerated; - runOption.SupportsVector512 = Vector512.IsHardwareAccelerated; - return runOption; } } diff --git a/Antigen/Expressions/ConstantValue.cs b/Antigen/Expressions/ConstantValue.cs index 2a3e09b..ddb88b1 100644 --- a/Antigen/Expressions/ConstantValue.cs +++ b/Antigen/Expressions/ConstantValue.cs @@ -166,6 +166,9 @@ public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList s_vectorGenericArgs = new() { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) }; + private static List s_allVectorMethods = null; + private static List s_allVectorTypes = null; - private void GenerateVectorMethods() + public static List GetAllVectorMethods() { - lock (Program.s_spinLock) - { - if (!isVectorMethodsInitialized) - { - s_allVectorMethods = new List(); - - RecordIntrinsicMethods(typeof(Vector)); - RecordIntrinsicMethods(typeof(Vector2)); - RecordIntrinsicMethods(typeof(Vector3)); - RecordIntrinsicMethods(typeof(Vector4)); - RecordVectorCtors(typeof(Vector2)); - RecordVectorCtors(typeof(Vector3)); - RecordVectorCtors(typeof(Vector4)); - - if (TC.Config.UseSve || Program.s_runOptions.SupportsVector64) - { - RecordIntrinsicMethods(typeof(Vector64)); - } - if (Program.s_runOptions.SupportsVector128) - { - RecordIntrinsicMethods(typeof(Vector128)); - } - if (Program.s_runOptions.SupportsVector256) - { - RecordIntrinsicMethods(typeof(Vector256)); - } - if (Program.s_runOptions.SupportsVector512) - { - RecordIntrinsicMethods(typeof(Vector512)); - } - if (System.Runtime.Intrinsics.X86.Aes.IsSupported) - { - RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); - } - if (Bmi1.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi1)); - } - if (Bmi1.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); - } - if (Bmi2.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi2)); - } - if (Bmi2.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); - } - if (Fma.IsSupported) - { - RecordIntrinsicMethods(typeof(Fma)); - } - if (Lzcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt)); - } - if (Lzcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); - } - if (Pclmulqdq.IsSupported) - { - RecordIntrinsicMethods(typeof(Pclmulqdq)); - } - if (Popcnt.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt)); - } - if (Popcnt.X64.IsSupported) - { - RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); - } - if (Avx.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx)); - } - if (Avx2.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx2)); - } - if (Avx512BW.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512BW)); - } - if (Avx512CD.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512CD)); - } - if (Avx512DQ.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512DQ)); - } - if (Avx512F.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512F)); - } - if (Avx512Vbmi.IsSupported) - { - RecordIntrinsicMethods(typeof(Avx512Vbmi)); - } - if (Sse.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse)); - } - if (Sse2.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse2)); - } - if (Sse3.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse3)); - } - if (Sse41.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse41)); - } - if (Sse42.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse42)); - } - if (Ssse3.IsSupported) - { - RecordIntrinsicMethods(typeof(Sse)); - } - if (AdvSimd.IsSupported || TC.Config.UseSve) - { - RecordIntrinsicMethods(typeof(AdvSimd)); - } - if (AdvSimd.Arm64.IsSupported || TC.Config.UseSve) - { - RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); - } - if (Sve.IsSupported || TC.Config.UseSve) - { - RecordIntrinsicMethods(typeof(Sve)); - } - isVectorMethodsInitialized = true; - } - } + Debug.Assert(s_allVectorMethods != null); + return s_allVectorMethods; + } - bool addAvx = PRNG.Decide(TC.Config.AvxMethodsProbability); - bool addSse = PRNG.Decide(TC.Config.SSEMethodsProbability); - bool addTraditional = PRNG.Decide(TC.Config.TraditionalMethodsProbability); - bool addSve = TC.Config.UseSve || PRNG.Decide(TC.Config.SveMethodsProbability); - bool addAdvsimd = TC.Config.UseSve || PRNG.Decide(TC.Config.AdvSimdMethodsProbability); + public static List GetAllVectorTypes() + { + Debug.Assert(s_allVectorTypes != null); + return s_allVectorTypes; + } - // Register all the vector create methods - foreach (var vectorMethod in s_allVectorMethods) + public static List GetVectorTypes(TestCase TC) + { + List vectorTypes = new(); + foreach (var vectorType in s_allVectorTypes) { - if (vectorMethod.IsVectorCreateMethod) + if (vectorType.IsVectorNumerics() || + vectorType.IsVectorTIntrinsics()) { - RegisterMethod(vectorMethod); - continue; + vectorTypes.Add(vectorType); } - bool isSve = vectorMethod.MethodName.StartsWith("Sve."); - bool isAdvSimd = vectorMethod.MethodName.StartsWith("AdvSimd."); - bool isAvx = vectorMethod.MethodName.StartsWith("Avx"); - bool isSse = vectorMethod.MethodName.StartsWith("Sse"); - bool isTraditional = vectorMethod.MethodName.StartsWith("Bmi") || - vectorMethod.MethodName.StartsWith("Fma") || - vectorMethod.MethodName.StartsWith("Lzcnt") || - vectorMethod.MethodName.StartsWith("Pclmulqdq") || - vectorMethod.MethodName.StartsWith("Popcnt"); if (TC.Config.UseSve) { - // If force-sve, then just add Sve/AdvSimd methods - if (isSve || isAdvSimd) + if (vectorType.IsVector64Intrinsics() || + vectorType.IsVector128Intrinsics()) { - RegisterMethod(vectorMethod); + vectorTypes.Add(vectorType); } } else { - if (addAdvsimd && isAdvSimd) - { - RegisterMethod(vectorMethod); - } - if (addSve && isSve) + if (Vector64.IsHardwareAccelerated && vectorType.IsVector64Intrinsics()) { - RegisterMethod(vectorMethod); + vectorTypes.Add(vectorType); } - if (addAvx && isAvx) + else if (Vector128.IsHardwareAccelerated && vectorType.IsVector128Intrinsics()) { - RegisterMethod(vectorMethod); + vectorTypes.Add(vectorType); } - if (addSse && isSse) + else if (Vector256.IsHardwareAccelerated && vectorType.IsVector256Intrinsics()) { - RegisterMethod(vectorMethod); + vectorTypes.Add(vectorType); } - if (addTraditional && isTraditional) + else if (Vector512.IsHardwareAccelerated && vectorType.IsVector512Intrinsics()) { - RegisterMethod(vectorMethod); + vectorTypes.Add(vectorType); } } } + return vectorTypes; + } + + private static void RecordVectorTypes() + { + s_allVectorTypes = + [ + new ValueType(VectorType.Vector64_Byte, "Vector64", "v64_byte"), + new ValueType(VectorType.Vector64_SByte, "Vector64", "v64_sbyte"), + new ValueType(VectorType.Vector64_Short, "Vector64", "v64_short"), + new ValueType(VectorType.Vector64_UShort, "Vector64", "v64_ushort"), + new ValueType(VectorType.Vector64_Int, "Vector64", "v64_int"), + new ValueType(VectorType.Vector64_UInt, "Vector64", "v64_uint"), + new ValueType(VectorType.Vector64_Long, "Vector64", "v64_long"), + new ValueType(VectorType.Vector64_ULong, "Vector64", "v64_ulong"), + new ValueType(VectorType.Vector64_Float, "Vector64", "v64_float"), + new ValueType(VectorType.Vector64_Double, "Vector64", "v64_double"), + new ValueType(VectorType.Vector128_Byte, "Vector128", "v128_byte"), + new ValueType(VectorType.Vector128_SByte, "Vector128", "v128_sbyte"), + new ValueType(VectorType.Vector128_Short, "Vector128", "v128_short"), + new ValueType(VectorType.Vector128_UShort, "Vector128", "v128_ushort"), + new ValueType(VectorType.Vector128_Int, "Vector128", "v128_int"), + new ValueType(VectorType.Vector128_UInt, "Vector128", "v128_uint"), + new ValueType(VectorType.Vector128_Long, "Vector128", "v128_long"), + new ValueType(VectorType.Vector128_ULong, "Vector128", "v128_ulong"), + new ValueType(VectorType.Vector128_Float, "Vector128", "v128_float"), + new ValueType(VectorType.Vector128_Double, "Vector128", "v128_double"), + new ValueType(VectorType.Vector256_Byte, "Vector256", "v256_byte"), + new ValueType(VectorType.Vector256_SByte, "Vector256", "v256_sbyte"), + new ValueType(VectorType.Vector256_Short, "Vector256", "v256_short"), + new ValueType(VectorType.Vector256_UShort, "Vector256", "v256_ushort"), + new ValueType(VectorType.Vector256_Int, "Vector256", "v256_int"), + new ValueType(VectorType.Vector256_UInt, "Vector256", "v256_uint"), + new ValueType(VectorType.Vector256_Long, "Vector256", "v256_long"), + new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong"), + new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float"), + new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double"), + new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte"), + new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte"), + new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short"), + new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort"), + new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int"), + new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint"), + new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long"), + new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong"), + new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float"), + new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double"), + new ValueType(VectorType.Vector_Byte, "Vector", "v_byte"), + new ValueType(VectorType.Vector_SByte, "Vector", "v_sbyte"), + new ValueType(VectorType.Vector_Short, "Vector", "v_short"), + new ValueType(VectorType.Vector_UShort, "Vector", "v_ushort"), + new ValueType(VectorType.Vector_Int, "Vector", "v_int"), + new ValueType(VectorType.Vector_UInt, "Vector", "v_uint"), + new ValueType(VectorType.Vector_Long, "Vector", "v_long"), + new ValueType(VectorType.Vector_ULong, "Vector", "v_ulong"), + new ValueType(VectorType.Vector_Float, "Vector", "v_float"), + new ValueType(VectorType.Vector_Double, "Vector", "v_double"), + new ValueType(VectorType.Vector2, "Vector2", "v2"), + new ValueType(VectorType.Vector3, "Vector3", "v3"), + new ValueType(VectorType.Vector4, "Vector4", "v4"), + ]; + } + + public static void RecordVectorMethods() + { + lock (Program.s_spinLock) + { + RecordVectorTypes(); + + s_allVectorMethods = new List(); + + RecordIntrinsicMethods(typeof(Vector)); + RecordIntrinsicMethods(typeof(Vector2)); + RecordIntrinsicMethods(typeof(Vector3)); + RecordIntrinsicMethods(typeof(Vector4)); + RecordVectorCtors(typeof(Vector2)); + RecordVectorCtors(typeof(Vector3)); + RecordVectorCtors(typeof(Vector4)); + RecordIntrinsicMethods(typeof(Vector64)); + RecordIntrinsicMethods(typeof(Vector128)); + RecordIntrinsicMethods(typeof(Vector256)); + RecordIntrinsicMethods(typeof(Vector512)); + RecordIntrinsicMethods(typeof(AdvSimd)); + RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + RecordIntrinsicMethods(typeof(Sve)); + RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); + RecordIntrinsicMethods(typeof(Bmi1)); + RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); + RecordIntrinsicMethods(typeof(Bmi2)); + RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + RecordIntrinsicMethods(typeof(Fma)); + RecordIntrinsicMethods(typeof(Lzcnt)); + RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); + RecordIntrinsicMethods(typeof(Pclmulqdq)); + RecordIntrinsicMethods(typeof(Popcnt)); + RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + RecordIntrinsicMethods(typeof(Avx)); + RecordIntrinsicMethods(typeof(Avx2)); + RecordIntrinsicMethods(typeof(Avx512BW)); + RecordIntrinsicMethods(typeof(Avx512CD)); + RecordIntrinsicMethods(typeof(Avx512DQ)); + RecordIntrinsicMethods(typeof(Avx512F)); + RecordIntrinsicMethods(typeof(Avx512Vbmi)); + RecordIntrinsicMethods(typeof(Sse)); + RecordIntrinsicMethods(typeof(Sse2)); + RecordIntrinsicMethods(typeof(Sse3)); + RecordIntrinsicMethods(typeof(Sse41)); + RecordIntrinsicMethods(typeof(Sse42)); + RecordIntrinsicMethods(typeof(Sse)); + } + } + + private static bool ShouldSkipVectorMethod(string fullMethodName) + { + // We do not support these types, so ignore these methods. + return fullMethodName.Contains("IntPtr") || fullMethodName.Contains("ValueTuple") || + fullMethodName.Contains("Matrix") || fullMethodName.Contains("Span") || + fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || + fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || + fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") || + /*fullMethodName.Contains("SveMaskPattern") ||*/ fullMethodName.Contains("SvePrefetchType") || + fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("FloatRoundingMode") || + fullMethodName.Contains("Unsafe"); } /// @@ -233,57 +212,60 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam vectorTypeName = vectorType.Name; } var methods = vectorType.GetMethods(BindingFlags.Public | BindingFlags.Static); - - foreach (var method in methods) + var genericMethods = methods.Where(m => m.IsGenericMethod); + var nonGenericMethods = methods.Where(m => !m.IsGenericMethod); + HashSet nonGenericAdded = new HashSet(); + foreach (var method in nonGenericMethods) { + string fullMethodName = method.ToString(); + if (method.IsSpecialName) { // special methods like properties / operators continue; } - string fullMethodName = method.ToString(); + if (ShouldSkipVectorMethod(fullMethodName)) + { + continue; + } - if (fullMethodName.Contains("IntPtr") || fullMethodName.Contains("ValueTuple") || - fullMethodName.Contains("Matrix") || fullMethodName.Contains("Span") || - fullMethodName.Contains("Quaternion") || fullMethodName.Contains("[]") || - fullMethodName.Contains("*") || fullMethodName.Contains("ByRef") || - fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") || - fullMethodName.Contains("SveMaskPattern") || fullMethodName.Contains("SvePrefetchType") || - fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("FloatRoundingMode") || - fullMethodName.Contains("Unsafe")) + s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, method)); + nonGenericAdded.Add(method.Name); + } + + foreach (var method in genericMethods) + { + if (nonGenericAdded.Contains(method.Name)) { - // We do not support these types, so ignore these methods. + // We have already added generic instances of this method. + // No need to add further + continue; } - string vectorsInMethod = Tree.ValueType.GetVectorList(fullMethodName); + if (method.IsSpecialName) + { + // special methods like properties / operators + continue; + } - // If a parameter is one of the vector that is not supported, then skip this method - if (vectorsInMethod != null) + string fullMethodName = method.ToString(); + + if (ShouldSkipVectorMethod(fullMethodName)) { - if (!Program.s_runOptions.SupportsVector64 && vectorsInMethod.Contains("64")) continue; - if (!Program.s_runOptions.SupportsVector128 && vectorsInMethod.Contains("128")) continue; - if (!Program.s_runOptions.SupportsVector256 && vectorsInMethod.Contains("256")) continue; - if (!Program.s_runOptions.SupportsVector512 && vectorsInMethod.Contains("512")) continue; + continue; } - if (method.IsGenericMethod) + if (method.GetGenericArguments().Count() == 1) { - if (method.GetGenericArguments().Count() == 1) + // Only instantiate generic single argument methods + foreach (var genericArgument in s_vectorGenericArgs) { - // Only instantiate generic single argument methods - foreach (var genericArgument in s_vectorGenericArgs) - { - var genericInitVectorMethod = method.MakeGenericMethod(genericArgument); - s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod)); - } + var genericInitVectorMethod = method.MakeGenericMethod(genericArgument); + s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod)); } } - else - { - s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, method)); - } } } @@ -364,5 +346,29 @@ private static void RecordVectorCtors(Type vectorType) } } + private static readonly Regex multipleVectorsRegex = new Regex(@"Vector(64|128|256|512)"); + + /// + /// Returns Vector length for given type. `null` if not a VectorType. + /// + /// + /// + public static string GetVectorList(string typeName) + { + var vectorTypeMatches = multipleVectorsRegex.Matches(typeName); + if (vectorTypeMatches.Count == 0) + { + return null; + } + + string result = "|"; + foreach (Match vectorTypeMatch in vectorTypeMatches) + { + Debug.Assert(vectorTypeMatch.Groups.Count == 2); + result += (vectorTypeMatch.Groups[1].Value + "|"); + } + + return result; + } } } diff --git a/Antigen/TestClass.cs b/Antigen/TestClass.cs index 7bce59b..f01d152 100644 --- a/Antigen/TestClass.cs +++ b/Antigen/TestClass.cs @@ -10,6 +10,8 @@ using System.Reflection; using System.Reflection.Metadata; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; using Antigen.Expressions; using Antigen.Statements; using Antigen.Tree; @@ -28,8 +30,6 @@ public partial class TestClass public TestCase TC { get; private set; } public Stack ScopeStack { get; private set; } private List> _methods { get; set; } - private static List s_allVectorMethods = null; - private static bool isVectorMethodsInitialized = false; private int _variableId; public string GetVariableName(Tree.ValueType variableType) @@ -52,6 +52,143 @@ public TestClass(TestCase tc, string className) _variableId = 0; } + private void GenerateVectorMethods() + { + bool addAvx = PRNG.Decide(TC.Config.AvxMethodsProbability); + bool addSse = PRNG.Decide(TC.Config.SSEMethodsProbability); + bool addTraditional = PRNG.Decide(TC.Config.TraditionalMethodsProbability); + bool addSve = TC.Config.UseSve || PRNG.Decide(TC.Config.SveMethodsProbability); + bool addAdvsimd = TC.Config.UseSve || PRNG.Decide(TC.Config.AdvSimdMethodsProbability); + + // Register all the vector create methods + foreach (var vectorMethod in VectorHelpers.GetAllVectorMethods()) + { + bool isVectorT = vectorMethod.MethodName.StartsWith("Vector."); + bool isVector2 = vectorMethod.MethodName.StartsWith("Vector2."); + bool isVector3 = vectorMethod.MethodName.StartsWith("Vector3."); + bool isVector4 = vectorMethod.MethodName.StartsWith("Vector4."); + bool isVector64 = vectorMethod.MethodName.StartsWith("Vector64."); + bool isVector128 = vectorMethod.MethodName.StartsWith("Vector128."); + bool isVector256 = vectorMethod.MethodName.StartsWith("Vector256."); + bool isVector512 = vectorMethod.MethodName.StartsWith("Vector512."); + + bool isSve = vectorMethod.MethodName.StartsWith("Sve."); + bool isAdvSimd = vectorMethod.MethodName.StartsWith("AdvSimd."); + bool isAdvSimdx64 = vectorMethod.MethodName.StartsWith("AdvSimd.X64."); + + bool isAvx = vectorMethod.MethodName.StartsWith("Avx."); + bool isAvx2 = vectorMethod.MethodName.StartsWith("Avx2."); + bool isAvx512BW = vectorMethod.MethodName.StartsWith("Avx512BW."); + bool isAvx512CD = vectorMethod.MethodName.StartsWith("Avx512CD."); + bool isAvx512DQ = vectorMethod.MethodName.StartsWith("Avx512DQ."); + bool isAvx512F = vectorMethod.MethodName.StartsWith("Avx512F."); + bool isAvx512Vbmi = vectorMethod.MethodName.StartsWith("Avx512Vbmi."); + + bool isSse = vectorMethod.MethodName.StartsWith("Sse."); + bool isSse2 = vectorMethod.MethodName.StartsWith("Sse2."); + bool isSse3 = vectorMethod.MethodName.StartsWith("Sse3."); + bool isSse41 = vectorMethod.MethodName.StartsWith("Sse41."); + bool isSse42 = vectorMethod.MethodName.StartsWith("Sse42."); + bool isSsse3 = vectorMethod.MethodName.StartsWith("Ssse3."); + + bool isBmi1 = vectorMethod.MethodName.StartsWith("Bmi1."); + bool isBmi1x64 = vectorMethod.MethodName.StartsWith("Bmi1.X64."); + bool isBmi2 = vectorMethod.MethodName.StartsWith("Bmi2."); + bool isBmi2x64 = vectorMethod.MethodName.StartsWith("Bmi2.X64."); + bool isFma = vectorMethod.MethodName.StartsWith("Fma."); + bool isLzcnt = vectorMethod.MethodName.StartsWith("Lzcnt."); + bool isLzcntx64 = vectorMethod.MethodName.StartsWith("Lzcnt.X64."); + bool isPclmulqdq = vectorMethod.MethodName.StartsWith("Pclmulqdq."); + bool isPopcnt = vectorMethod.MethodName.StartsWith("Popcnt."); + bool isPopcntx64 = vectorMethod.MethodName.StartsWith("Popcnt.X64."); + + string vectorsInMethod = VectorHelpers.GetVectorList(vectorMethod.ToString()); + if (vectorsInMethod != null) + { + // If a parameter is one of the vector that is not supported, then skip this method + if (TC.Config.UseSve) + { + if (vectorsInMethod.Contains("256") || vectorsInMethod.Contains("512")) + { + continue; + } + } + else + { + if (!Vector64.IsHardwareAccelerated && vectorsInMethod.Contains("64")) continue; + if (!Vector128.IsHardwareAccelerated && vectorsInMethod.Contains("128")) continue; + if (!Vector256.IsHardwareAccelerated && vectorsInMethod.Contains("256")) continue; + if (!Vector512.IsHardwareAccelerated && vectorsInMethod.Contains("512")) continue; + } + } + + if (isVectorT || isVector2 || isVector3 || isVector4) + { + RegisterMethod(vectorMethod); + continue; + } + + else if (TC.Config.UseSve) + { + // If force-sve, then just add Sve/AdvSimd methods + if (isSve || isAdvSimd || isVector64 || isVector128) + { + RegisterMethod(vectorMethod); + } + } + else + { + if ( + (isVector64 && Vector64.IsHardwareAccelerated) + || + (isVector128 && Vector128.IsHardwareAccelerated) + || + (isVector256 && Vector256.IsHardwareAccelerated) + || + (isVector512 && Vector512.IsHardwareAccelerated) + || + (addSve && Sve.IsSupported) + || + (addAdvsimd && + ((isAdvSimd && AdvSimd.IsSupported) || + (isAdvSimdx64 && AdvSimd.Arm64.IsSupported))) + || + (addAvx && + ((isAvx && Avx.IsSupported) || + (isAvx2 && Avx2.IsSupported) || + (isAvx512BW && Avx512BW.IsSupported) || + (isAvx512CD && Avx512CD.IsSupported) || + (isAvx512DQ && Avx512DQ.IsSupported) || + (isAvx512F && Avx512F.IsSupported) || + (isAvx512Vbmi && Avx512Vbmi.IsSupported))) + || + (addSse && + ((isSse && Sse.IsSupported) || + (isSse2 && Sse2.IsSupported) || + (isSse3 && Sse3.IsSupported) || + (isSse41 && Sse41.IsSupported) || + (isSse42 && Sse42.IsSupported) || + (isSsse3 && Ssse3.IsSupported))) + || + (addTraditional && + ((isBmi1 && Bmi1.IsSupported) || + (isBmi1x64 && Bmi1.X64.IsSupported) || + (isBmi2 && Bmi2.IsSupported) || + (isBmi2x64 && Bmi2.X64.IsSupported) || + (isFma && Fma.IsSupported) || + (isLzcnt && Lzcnt.IsSupported) || + (isLzcntx64 && Lzcnt.X64.IsSupported) || + (isPclmulqdq && Pclmulqdq.IsSupported) || + (isPopcnt && Popcnt.IsSupported) || + (isPopcntx64 && Popcnt.X64.IsSupported))) + ) + { + RegisterMethod(vectorMethod); + } + } + } + } + /// /// Register method /// @@ -326,7 +463,7 @@ private List GenerateFields(bool isStatic) if (TC.ContainsVectorData) { - foreach (Tree.ValueType variableType in Tree.ValueType.GetVectorTypes()) + foreach (Tree.ValueType variableType in VectorHelpers.GetVectorTypes(TC)) { Debug.Assert(variableType.IsVectorType); string variableName = (isStatic ? "s_" : string.Empty) + GetVariableName(variableType); diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 520f8bf..1fb2df7 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -375,7 +375,13 @@ public Statement StatementHelper(StmtKind stmtKind, int depth) PushScope(new Scope(TC, ScopeKind.LoopScope, CurrentScope)); var bounds = ExprHelper(GetASTUtils().GetRandomExpressionReturningValueType(Primitive.Int), Tree.ValueType.ForPrimitive(Primitive.Int), 0); - var loopStepCastExpr = ExprHelper(ExprKind.AssignExpression, Tree.ValueType.GetRandomType(), 0) as CastExpression; + Tree.ValueType loopStepType; + do + { + loopStepType = Tree.ValueType.GetRandomType(); + } while (loopStepType.PrimitiveType == Primitive.SveMaskPattern); + + var loopStepCastExpr = ExprHelper(ExprKind.AssignExpression, loopStepType, 0) as CastExpression; // No need to cast the assign expression inside for-loop. Additionally compiler would complain for it, so just // unwrap the cast expression and use the real assignment expression. @@ -697,6 +703,11 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep { //Debug.Assert(depth <= TC.Config.MaxExprDepth); + if (exprType.PrimitiveType == Primitive.SveMaskPattern) + { + exprKind = PRNG.Decide(0.5) ? ExprKind.LiteralExpression : ExprKind.VariableExpression; + } + switch (exprKind) { case ExprKind.LiteralExpression: diff --git a/Antigen/Tree/AstUtils.cs b/Antigen/Tree/AstUtils.cs index 3729da9..c0722cf 100644 --- a/Antigen/Tree/AstUtils.cs +++ b/Antigen/Tree/AstUtils.cs @@ -37,7 +37,7 @@ public AstUtils(TestCase tc, ConfigOptions configOptions, RunOptions runOptions) if (TestCase.ContainsVectorData) { - foreach (ValueType type in ValueType.GetVectorTypes()) + foreach (ValueType type in VectorHelpers.GetVectorTypes(TestCase)) { AllTypes.Add(new Weights(type, ConfigOptions.Lookup(type))); } diff --git a/Antigen/Tree/Scope.cs b/Antigen/Tree/Scope.cs index 593b037..68b5b98 100644 --- a/Antigen/Tree/Scope.cs +++ b/Antigen/Tree/Scope.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Antigen.Statements; diff --git a/Antigen/Tree/Types.cs b/Antigen/Tree/Types.cs index ffa91a0..0fbef45 100644 --- a/Antigen/Tree/Types.cs +++ b/Antigen/Tree/Types.cs @@ -32,7 +32,7 @@ public enum Primitive : ulong String = 0x2000, Struct = 0x4000, - // SveMaskPattern = 0x8000, + SveMaskPattern = 0x8000, Numeric = Byte | SByte | Short | UShort | Int | UInt | Long | ULong | Float | Double | Decimal /*| SveMaskPattern*/, SignedInteger = SByte | Short | Int | Long, @@ -118,11 +118,37 @@ public bool IsVectorNumerics() return false; } - public bool IsVectorIntrinsics() + public bool IsVectorTIntrinsics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector_Byte && VectorType <= VectorType.Vector_Double) + { + return true; + } + } + + return false; + } + + public bool IsVector64Intrinsics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector64_Double) + { + return true; + } + } + + return false; + } + + public bool IsVector128Intrinsics() { if (IsVectorType) { - if (VectorType >= VectorType.Vector64_Byte && VectorType <= VectorType.Vector_Double) + if (VectorType >= VectorType.Vector128_Byte && VectorType <= VectorType.Vector128_Double) { return true; } @@ -131,6 +157,37 @@ public bool IsVectorIntrinsics() return false; } + public bool IsVector256Intrinsics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector256_Byte && VectorType <= VectorType.Vector256_Double) + { + return true; + } + } + + return false; + } + + public bool IsVector512Intrinsics() + { + if (IsVectorType) + { + if (VectorType >= VectorType.Vector512_Byte && VectorType <= VectorType.Vector512_Double) + { + return true; + } + } + + return false; + } + + public bool IsVectorIntrinsics() + { + return IsVectorTIntrinsics() || IsVector64Intrinsics() || IsVector128Intrinsics() || IsVector256Intrinsics() || IsVector512Intrinsics(); + } + // TODO: Matrix about implicit and explicit cast public bool AllowedPrimitive(Primitive primitives) @@ -171,7 +228,7 @@ private ValueType(Primitive valueType, string displayText, SyntaxKind typeKind) VectorType = 0; } - private ValueType(VectorType vectorType, string displayText, string variableNameHint) + public ValueType(VectorType vectorType, string displayText, string variableNameHint) { VectorType = vectorType; _displayText = displayText; @@ -196,111 +253,10 @@ private ValueType(VectorType vectorType, string displayText, string variableName new ValueType(Primitive.UShort, "ushort", SyntaxKind.UShortKeyword), new ValueType(Primitive.UInt, "uint", SyntaxKind.UIntKeyword), new ValueType(Primitive.ULong, "ulong", SyntaxKind.ULongKeyword), - // new ValueType(Primitive.SveMaskPattern, "SveMaskPattern", SyntaxKind.EnumKeyword), + new ValueType(Primitive.SveMaskPattern, "SveMaskPattern", SyntaxKind.EnumKeyword), }; - private static readonly List s_vectorTypes = new(); - - static ValueType() - { - if (Program.s_runOptions.SupportsVector64) - { - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Byte, "Vector64", "v64_byte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_SByte, "Vector64", "v64_sbyte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Short, "Vector64", "v64_short")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_UShort, "Vector64", "v64_ushort")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Int, "Vector64", "v64_int")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_UInt, "Vector64", "v64_uint")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Long, "Vector64", "v64_long")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_ULong, "Vector64", "v64_ulong")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Float, "Vector64", "v64_float")); - s_vectorTypes.Add(new ValueType(VectorType.Vector64_Double, "Vector64", "v64_double")); - } - - if (Program.s_runOptions.SupportsVector128) - { - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Byte, "Vector128", "v128_byte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_SByte, "Vector128", "v128_sbyte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Short, "Vector128", "v128_short")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_UShort, "Vector128", "v128_ushort")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Int, "Vector128", "v128_int")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_UInt, "Vector128", "v128_uint")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Long, "Vector128", "v128_long")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_ULong, "Vector128", "v128_ulong")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Float, "Vector128", "v128_float")); - s_vectorTypes.Add(new ValueType(VectorType.Vector128_Double, "Vector128", "v128_double")); - } - - if (Program.s_runOptions.SupportsVector256) - { - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Byte, "Vector256", "v256_byte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_SByte, "Vector256", "v256_sbyte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Short, "Vector256", "v256_short")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_UShort, "Vector256", "v256_ushort")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Int, "Vector256", "v256_int")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_UInt, "Vector256", "v256_uint")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Long, "Vector256", "v256_long")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_ULong, "Vector256", "v256_ulong")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Float, "Vector256", "v256_float")); - s_vectorTypes.Add(new ValueType(VectorType.Vector256_Double, "Vector256", "v256_double")); - } - - if (Program.s_runOptions.SupportsVector512) - { - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Byte, "Vector512", "v512_byte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_SByte, "Vector512", "v512_sbyte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Short, "Vector512", "v512_short")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_UShort, "Vector512", "v512_ushort")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Int, "Vector512", "v512_int")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_UInt, "Vector512", "v512_uint")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Long, "Vector512", "v512_long")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_ULong, "Vector512", "v512_ulong")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Float, "Vector512", "v512_float")); - s_vectorTypes.Add(new ValueType(VectorType.Vector512_Double, "Vector512", "v512_double")); - } - - - s_vectorTypes.Add(new ValueType(VectorType.Vector_Byte, "Vector", "v_byte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_SByte, "Vector", "v_sbyte")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_Short, "Vector", "v_short")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_UShort, "Vector", "v_ushort")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_Int, "Vector", "v_int")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_UInt, "Vector", "v_uint")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_Long, "Vector", "v_long")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_ULong, "Vector", "v_ulong")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_Float, "Vector", "v_float")); - s_vectorTypes.Add(new ValueType(VectorType.Vector_Double, "Vector", "v_double")); - - s_vectorTypes.Add(new ValueType(VectorType.Vector2, "Vector2", "v2")); - s_vectorTypes.Add(new ValueType(VectorType.Vector3, "Vector3", "v3")); - s_vectorTypes.Add(new ValueType(VectorType.Vector4, "Vector4", "v4")); - } - private static readonly Regex vectorRegex = new Regex(@"Vector(64|128|256|512)?`1\[(.*)\]"); - private static readonly Regex multipleVectorsRegex = new Regex(@"Vector(64|128|256|512)`1"); - - /// - /// Returns Vector length for given type. `null` if not a VectorType. - /// - /// - /// - public static string GetVectorList(string typeName) - { - var vectorTypeMatches = multipleVectorsRegex.Matches(typeName); - if (vectorTypeMatches.Count == 0) - { - return null; - } - - string result = "|"; - foreach (Match vectorTypeMatch in vectorTypeMatches) - { - Debug.Assert(vectorTypeMatch.Groups.Count == 2); - result += (vectorTypeMatch.Groups[1].Value + "|"); - } - - return result; - } public static ValueType ParseType(string typeName) { @@ -386,7 +342,7 @@ public static ValueType ParseType(string typeName) }, _ => throw new Exception("Invalid vector length"), }; - return s_vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + return VectorHelpers.GetAllVectorTypes().FirstOrDefault(v => v.VectorType == parsedVectorType); } else if (typeName.Contains("System.Numerics")) { @@ -397,12 +353,12 @@ public static ValueType ParseType(string typeName) "System.Numerics.Vector4" => VectorType.Vector4, _ => throw new Exception("Invalid vector type Vector"), }; - return s_vectorTypes.FirstOrDefault(v => v.VectorType == parsedVectorType); + return VectorHelpers.GetAllVectorTypes().FirstOrDefault(v => v.VectorType == parsedVectorType); + } + else if (typeName == "System.Runtime.Intrinsics.Arm.SveMaskPattern") + { + return types.FirstOrDefault(t => t.PrimitiveType == Primitive.SveMaskPattern); } - // else if (typeName == "System.Runtime.Intrinsics.Arm.SveMaskPattern") - // { - // return types.FirstOrDefault(t => t.PrimitiveType == Primitive.SveMaskPattern); - // } else { var parsedPrimitiveType = typeName switch @@ -580,11 +536,6 @@ public static List GetTypes() return types; } - public static List GetVectorTypes() - { - return s_vectorTypes; - } - public static ValueType GetRandomType() { return types[PRNG.Next(types.Count)]; From f14d81130cc960833b19a25c66fd1e6903c26070 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 5 Aug 2024 21:10:50 -0700 Subject: [PATCH 124/149] Make Trimmer as .net9 --- Trimmer/Trimmer.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index aecef22..b1ead82 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -2,7 +2,8 @@ Exe - net8.0 + net9.0 + True From d8e55382bc603014fd0dd5e8da598e6f0da51a3a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 5 Aug 2024 21:11:39 -0700 Subject: [PATCH 125/149] comment compiler error generation code --- Antigen/TestCase.cs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index a3b9dbc..6360bce 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -115,19 +115,21 @@ public TestResult Verify() CompileResult compileResult = s_testRunner.Compile(syntaxTree, Name); if (compileResult.AssemblyFullPath == null) { - //StringBuilder fileContents = new StringBuilder(); - - //fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); - //fileContents.AppendLine("/*"); - //fileContents.AppendLine($"Got {compileResult.CompileErrors.Count()} compiler error(s):"); - //foreach (var error in compileResult.CompileErrors) - //{ - // fileContents.AppendLine(error.ToString()); - //} - //fileContents.AppendLine("*/"); - - //string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); - //File.WriteAllText(errorFile, fileContents.ToString()); +#if UNREACHABLE + StringBuilder fileContents = new StringBuilder(); + + fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); + fileContents.AppendLine("/*"); + fileContents.AppendLine($"Got {compileResult.CompileErrors.Count()} compiler error(s):"); + foreach (var error in compileResult.CompileErrors) + { + fileContents.AppendLine(error.ToString()); + } + fileContents.AppendLine("*/"); + + string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); + File.WriteAllText(errorFile, fileContents.ToString()); +#endif return compileResult.RoslynException != null ? TestResult.RoslynException : TestResult.CompileError; } #if UNREACHABLE From e97e92fabe5a49130f7a6059a8b95063fb9486af Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 5 Aug 2024 21:57:20 -0700 Subject: [PATCH 126/149] track hitcount --- Antigen/TestCase.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 6360bce..42051d0 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -40,12 +40,19 @@ private struct UniqueIssueFile public readonly int UniqueIssueId; public readonly int FileSize; public readonly string FileName; + public int HitCount { get; private set; } - public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName) + public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName, int hitCount) { UniqueIssueId = _uniqueIssueId; FileSize = _fileSize; FileName = _fileName; + HitCount = hitCount; + } + + public void IncreaseHitCount() + { + HitCount++; } } private static readonly ConcurrentDictionary s_uniqueIssues = new(); @@ -311,6 +318,7 @@ private void SaveTestCase( fileContents.AppendLine("*/"); string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; + StringBuilder summaryContents = new StringBuilder(output); string uniqueIssueDirName = null; int assertionHashCode = failureText.GetHashCode(); string currentReproFile = $"{testFileName}.g.cs"; @@ -319,12 +327,17 @@ private void SaveTestCase( UniqueIssueFile uniqueIssueFile; if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { - uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile); + uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile, 0); } else { uniqueIssueFile = s_uniqueIssues[assertionHashCode]; } + uniqueIssueFile.IncreaseHitCount(); + summaryContents.AppendLine(); + summaryContents.AppendLine(); + summaryContents.AppendLine($"HitCount: {uniqueIssueFile.HitCount}"); + // Create hash of testAssertion and copy files in respective bucket. uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{uniqueIssueFile.UniqueIssueId}"); @@ -332,9 +345,10 @@ private void SaveTestCase( if (!Directory.Exists(uniqueIssueDirName)) { Directory.CreateDirectory(uniqueIssueDirName); - File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), output); } + File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), summaryContents.ToString()); + // Only cache 1 file of smallest possible size. if (uniqueIssueFile.FileSize > fileContents.Length) { @@ -344,13 +358,12 @@ private void SaveTestCase( File.Delete(largerReproFile); } - // Write the smallest file string failFile = Path.Combine(uniqueIssueDirName, currentReproFile); File.WriteAllText(failFile, fileContents.ToString()); // Update the file size - s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(uniqueIssueFile.UniqueIssueId, fileContents.Length, currentReproFile); + s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(uniqueIssueFile.UniqueIssueId, fileContents.Length, currentReproFile, uniqueIssueFile.HitCount); } } } From b5746b6424f35d50e205df34e348aa98e412ab26 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 08:24:27 -0700 Subject: [PATCH 127/149] Implement Execution engine (#6) * Use Exection Engine to speed up execution * fix bugs and pass environment variables * make sure EEProxy is started * Give credits to Fuzzlyn * Use Execution Engine for Trimmer * fix bug --- Antigen.sln | 6 + Antigen/Antigen.cs | 62 ++++-- Antigen/Antigen.csproj | 6 +- Antigen/Compilation/CompileResult.cs | 43 ++++ Antigen/Compilation/Compiler.cs | 98 +++++++++ Antigen/Config/ConfigOptions.cs | 2 +- Antigen/Execution/EEDriver.cs | 124 +++++++++++ Antigen/Execution/EEProxy.cs | 183 ++++++++++++++++ Antigen/Execution/ExecuteResult.cs | 73 +++++++ Antigen/Helpers/PreGenerated.cs | 10 +- Antigen/Helpers/VectorHelpers.cs | 90 ++++---- Antigen/TestCase.cs | 259 +++++++++------------- ExecutionEngine/DynamicAssemblyLoader.cs | 30 +++ ExecutionEngine/ExecutionEngine.csproj | 18 ++ ExecutionEngine/Program.cs | 170 +++++++++++++++ ExecutionEngine/RequestResponse.cs | 31 +++ ExecutionEngine/RunResult.cs | 33 +++ README.md | 6 +- Trimmer/TestTrimmer.cs | 266 +++++++++++------------ Trimmer/Trimmer.csproj | 12 + Utils/TestRunner.cs | 243 +++++---------------- 21 files changed, 1211 insertions(+), 554 deletions(-) create mode 100644 Antigen/Compilation/CompileResult.cs create mode 100644 Antigen/Compilation/Compiler.cs create mode 100644 Antigen/Execution/EEDriver.cs create mode 100644 Antigen/Execution/EEProxy.cs create mode 100644 Antigen/Execution/ExecuteResult.cs create mode 100644 ExecutionEngine/DynamicAssemblyLoader.cs create mode 100644 ExecutionEngine/ExecutionEngine.csproj create mode 100644 ExecutionEngine/Program.cs create mode 100644 ExecutionEngine/RequestResponse.cs create mode 100644 ExecutionEngine/RunResult.cs diff --git a/Antigen.sln b/Antigen.sln index bbeb1ea..dc69bf1 100644 --- a/Antigen.sln +++ b/Antigen.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trimmer", "Trimmer\Trimmer.csproj", "{CE027BEA-870D-4821-886E-71E3F209A18B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{1A2BB825-9952-479B-8F6A-7F0543B0A4FC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {CE027BEA-870D-4821-886E-71E3F209A18B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE027BEA-870D-4821-886E-71E3F209A18B}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE027BEA-870D-4821-886E-71E3F209A18B}.Release|Any CPU.Build.0 = Release|Any CPU + {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index a08bf6d..6f588b6 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -8,6 +8,8 @@ using Utils; using System.Linq; using System.Runtime.CompilerServices; +using Antigen.Execution; +using System.Reflection; namespace Antigen { @@ -26,6 +28,8 @@ class Program { TestResult.OutputMismatch, 0 }, { TestResult.Pass, 0 }, { TestResult.OOM, 0 }, + { TestResult.OtherError, 0 }, + { TestResult.Timeout, 0 }, }; private static int s_testId = 0; @@ -71,7 +75,7 @@ private static int Run(CommandLineOptions opts) Directory.CreateDirectory(s_runOptions.OutputDirectory); } - Parallel.For(0, 2, (p) => RunTest()); + Parallel.For(0, 4, (p) => RunTest()); Console.WriteLine($"Executed {s_testId} test cases."); DisplayStats(); } @@ -163,43 +167,55 @@ static void RunTest() { TestResult.OutputMismatch, 0 }, { TestResult.Pass, 0 }, { TestResult.OOM, 0 }, + { TestResult.OtherError, 0 }, + { TestResult.Timeout, 0 }, }; - // Generate vector methods - VectorHelpers.RecordVectorMethods(); + lock (s_spinLock) + { + if (TestCase.s_RunOptions == null) + { + TestCase.s_RunOptions = s_runOptions; + TestCase.s_Driver = EEDriver.GetInstance(s_runOptions.CoreRun, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), () => EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), false)); + TestCase.s_TestRunner = TestRunner.GetInstance(TestCase.s_Driver, s_runOptions.CoreRun, s_runOptions.OutputDirectory); + + // Generate vector methods + VectorHelpers.RecordVectorMethods(); + } + } int testCount = 0; while (!Done) { var currTestId = GetNextTestId(); - var testCase = new TestCase(currTestId, s_runOptions); - testCase.Generate(); - string configName = testCase.Config.Name; - if (testCase.ContainsVectorData) - { - configName += " (Vector)"; - } - if (testCase.Config.UseSve) + using (var testCase = new TestCase(currTestId, s_runOptions)) { - configName += " (SVE)"; + testCase.Generate(); + string configName = testCase.Config.Name; + if (testCase.ContainsVectorData) + { + configName += " (Vector)"; + } + if (testCase.Config.UseSve) + { + configName += " (SVE)"; + } + var result = testCase.Verify(); + + Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", + currTestId, + configName, + Enum.GetName(typeof(TestResult), result), + (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, + (DateTime.Now - s_startTime).ToString()); + localStats[result]++; } - var result = testCase.Verify(); - Console.WriteLine("[{4}] Test# {0, -5} [{1, -25}] - {2, -15} {3, -10} MB ", - currTestId, - configName, - Enum.GetName(typeof(TestResult), result), - (double)Process.GetCurrentProcess().WorkingSet64 / 1000000, - (DateTime.Now - s_startTime).ToString()); - testCount++; - localStats[result]++; if (testCount == 50) { SaveResult(localStats, testCount); testCount = 0; } - - GC.Collect(); } } } diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index 8d776b4..7e56303 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -12,7 +12,7 @@ - + @@ -31,6 +31,10 @@ + + + + PreserveNewest diff --git a/Antigen/Compilation/CompileResult.cs b/Antigen/Compilation/CompileResult.cs new file mode 100644 index 0000000..bdf3c31 --- /dev/null +++ b/Antigen/Compilation/CompileResult.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; + +namespace Antigen.Compilation +{ + internal struct CompileResult + { + public CompileResult(IEnumerable diagnostics) + { + CompileErrors = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Error); + CompileWarnings = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Warning); + } + + public CompileResult(string assemblyName, string assemblyFullPath, byte[] debugMs, byte[] releaseMs) + { + AssemblyName = assemblyName; + AssemblyFullPath = assemblyFullPath; + DebugAssembly = debugMs; + ReleaseAssembly = releaseMs; + } + + public CompileResult(Exception roslynException) + { + RoslynException = roslynException; + } + + public string AssemblyName { get; } + public Exception RoslynException { get; } + public IEnumerable CompileErrors { get; } + public IEnumerable CompileWarnings { get; } + public string AssemblyFullPath { get; } + public byte[] DebugAssembly { get; } + public byte[] ReleaseAssembly { get; } + } +} diff --git a/Antigen/Compilation/Compiler.cs b/Antigen/Compilation/Compiler.cs new file mode 100644 index 0000000..de3c0ca --- /dev/null +++ b/Antigen/Compilation/Compiler.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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antigen.Execution; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis; + +namespace Antigen.Compilation +{ + internal class Compiler + { + private static readonly CSharpCompilationOptions ReleaseCompileOptions = new( + OutputKind.ConsoleApplication, + concurrentBuild: true, + optimizationLevel: OptimizationLevel.Release); + + private static readonly CSharpCompilationOptions DebugCompileOptions = new( + OutputKind.ConsoleApplication, + concurrentBuild: true, + optimizationLevel: OptimizationLevel.Debug); + + private static readonly string s_corelibPath = typeof(object).Assembly.Location; + private static readonly MetadataReference[] s_references = +{ + MetadataReference.CreateFromFile(s_corelibPath), + MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(s_corelibPath), "System.Console.dll")), + MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(s_corelibPath), "System.Runtime.dll")), + MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location), + MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location), + }; + + private readonly string m_outputDirectory; + + internal Compiler(string outputDirectory) + { + m_outputDirectory = outputDirectory; + } + + internal CompileResult Compile(SyntaxTree programTree, string assemblyName) + { + var debugBytes = CompileAndGetBytes(programTree, assemblyName, DebugCompileOptions); + var releaseBytes = CompileAndGetBytes(programTree, assemblyName, ReleaseCompileOptions); + return new CompileResult(assemblyName, null, debugBytes, releaseBytes); + } + + private byte[] CompileAndGetBytes(SyntaxTree programTree, string assemblyName, CSharpCompilationOptions options) + { + string tag = options.OptimizationLevel == OptimizationLevel.Debug ? "Debug" : "Release"; + var cc = CSharpCompilation.Create($"{assemblyName}-{tag}.exe", new SyntaxTree[] { programTree }, s_references, options); + + using (var ms = new MemoryStream()) + { + EmitResult result; + try + { + result = cc.Emit(ms); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return null; + } + + if (!result.Success) + { +#if DEBUG + SaveCompilationError(programTree, result.Diagnostics); +#endif + return null; + } + + ms.Seek(0, SeekOrigin.Begin); + + return ms.ToArray(); + } + } + + private void SaveCompilationError(SyntaxTree tree, IEnumerable diagnostics) + { + StringBuilder fileContents = new StringBuilder(); + + fileContents.AppendLine(tree.GetRoot().NormalizeWhitespace().ToFullString()); + fileContents.AppendLine("/*"); + fileContents.AppendLine($"Got {diagnostics.Count()} compiler error(s):"); + var errorLines = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(diag => $"{diag.Location.GetLineSpan().StartLinePosition.Line}: {diag.GetMessage()}"); + var errorFile = Path.Combine(m_outputDirectory, $"{tree.FilePath}.error"); + File.WriteAllLines(errorFile, errorLines); + } + } +} diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index e55df06..f2b0c02 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -313,7 +313,7 @@ public class ConfigOptions /// /// AdvSimd methods probability /// - public double SveMethodsProbability = 0.5; + public double SveMethodsProbability = 0.0; /// /// Probability in which vector methods will be included. diff --git a/Antigen/Execution/EEDriver.cs b/Antigen/Execution/EEDriver.cs new file mode 100644 index 0000000..70d8436 --- /dev/null +++ b/Antigen/Execution/EEDriver.cs @@ -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. + +using System; +using System.Linq; +using System.Collections.Generic; +using ExecutionEngine; + +namespace Antigen.Execution +{ + // Driver that creates EEProxy instances and responsible for its lifetime. + internal class EEDriver + { + private readonly string _hostName; + private readonly string _executionEngine; + private Func> _envVarsGen; + + public static EEDriver GetInstance(string host, string executionEngine, Func> envVarGen) + { + return new EEDriver(host, executionEngine, envVarGen); + } + + private EEDriver(string host, string executionEngine, Func> envVarGen) + { + _hostName = host; + _executionEngine = executionEngine; + _envVarsGen = envVarGen; + + AppDomain.CurrentDomain.ProcessExit += (sender, args) => TerminateAllProxys(); + AppDomain.CurrentDomain.UnhandledException += (sender, args) => TerminateAllProxys(); + } + + private void TerminateAllProxys() + { + for (int i = 0; i < Proxys.Count; i++) + { + Proxys[i].Dispose(); + } + } + + public List Proxys { get; } = []; + + private EEProxy Get() + { + lock(Proxys) + { + if (Proxys.Count > 0) + { + int leastUsedIndex = 0; + for (int i = 1; i < Proxys.Count; i++) + { + if (Proxys[leastUsedIndex].LastUsedTime.Elapsed > Proxys[i].LastUsedTime.Elapsed) + { + leastUsedIndex = i; + } + } + var proxy = Proxys[leastUsedIndex]; + Proxys[leastUsedIndex] = Proxys[Proxys.Count - 1]; + Proxys.RemoveAt(Proxys.Count - 1); + return proxy; + } + } + + while (true) + { + var envVars = _envVarsGen(); + var proxy = EEProxy.GetInstance(_hostName, _executionEngine, envVars); + if (proxy.IsRunning) + { + return proxy; + } + } + } + + private void Return(EEProxy proxy) + { + List toRemove; + lock(Proxys) + { + toRemove = Proxys.Where(p => p.ShouldRecycle()).ToList(); + Proxys.RemoveAll(toRemove.Contains); + Proxys.Add(proxy); + } + + foreach (var p in toRemove) + { + p.Dispose(); + } + } + + /// + /// Execute the compiled assembly. + /// + /// + /// + internal Response Execute(Request request) + { + EEProxy proxy = null; + try + { + proxy = Get(); + var response = proxy.Execute(request); + if (response == null || response.HasCrashed || response.IsTimeout) + { + proxy = null; + } + else if (response.IsJitAssert || (response.DebugOutput != response.ReleaseOutput)) + { + response.EnvironmentVariables = proxy.GetEnvironmentVariables(); + } + return response; + } + finally + { + if (proxy != null) + { + Return(proxy); + } + } + } + + } +} diff --git a/Antigen/Execution/EEProxy.cs b/Antigen/Execution/EEProxy.cs new file mode 100644 index 0000000..2cc918c --- /dev/null +++ b/Antigen/Execution/EEProxy.cs @@ -0,0 +1,183 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +//using Antigen.Config; +using ExecutionEngine; +using Newtonsoft.Json; +using Utils; + +namespace Antigen.Execution +{ + // Each instance of class represents a corresponding instance of ExecutionEngine + internal class EEProxy + { + public readonly Process _process; + public Stopwatch LastUsedTime { get; } = new Stopwatch(); + private ReadOnlyDictionary _envVars; + private IReadOnlyList> _envVarsList; + private int _testCaseExecutionCount = 0; + + private static readonly TimeSpan s_inactivityPeriod = TimeSpan.FromMinutes(3); + private const int RecycleCount = 100; + private const int TimeoutInSeconds = 10; + + private EEProxy(string host, string executionEngine, Dictionary envVars) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = host, + Arguments = $"{executionEngine} {Environment.ProcessId}", // Optional: arguments for the process + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + _process = new Process + { + StartInfo = startInfo + }; + + SetEnvironmentVariables(startInfo, envVars); + _process.Start(); + _testCaseExecutionCount = 0; + } + + private void SetEnvironmentVariables(ProcessStartInfo startInfo, Dictionary envVars) + { + envVars["DOTNET_TieredCompilation"] = "0"; + envVars["DOTNET_JitThrowOnAssertionFailure"] = "1"; + envVars["DOTNET_LegacyExceptionHandling"] = "1"; + + foreach (var envVar in envVars) + { + startInfo.Environment[envVar.Key] = envVar.Value; + } + + _envVars = new ReadOnlyDictionary(envVars); + _envVarsList = envVars.Select(kv => new Tuple(kv.Key, kv.Value)).ToList(); + } + + public override string ToString() + { + string result = ""; + if (_process.HasExited) + { + result += "~"; + } + else + { + result += _process.Id; + } + result += $" [{LastUsedTime.Elapsed}]"; + return result; + } + + internal static EEProxy GetInstance(string host, string executionEngine, Dictionary envVars) + { + if (!File.Exists(host) || !File.Exists(executionEngine)) + { + throw new FileNotFoundException($"'{host}' or '{executionEngine}' not found."); + } + + return new EEProxy(host, executionEngine, envVars); + } + + public Response Execute(Request request) + { + _process.StandardInput.WriteLine(JsonConvert.SerializeObject(request)); + + bool killed = false; + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(TimeoutInSeconds)); + using var reg = cts.Token.Register(() => { killed = true; Kill(); }); + StringBuilder responseReader = new StringBuilder(); + while (true) + { + string line = _process.StandardOutput.ReadLine(); + if ((line == null) || (line == "Done")) + { + break; + } + responseReader.AppendLine(line); + } + _testCaseExecutionCount++; + LastUsedTime.Restart(); + + if (killed) + { + return new Response + { + IsTimeout = true + }; + } + + try + { + return JsonConvert.DeserializeObject(responseReader.ToString()); + } + catch (JsonException) + { + return new() + { + HasCrashed = true + }; + } + } + + /// + /// Returns environment variables used by this process. + /// + /// + public IReadOnlyList> GetEnvironmentVariables() + { + return _envVarsList; + } + + public void Kill() + { + if (!_process.HasExited) + { + _process.Kill(); + } + } + + public void Dispose() + { + if (!_process.HasExited) + { + _process.Kill(); + _process.Dispose(); + } + } + + /// + /// Recycle if it ran around {RecycleCount} test cases or has been inactive for 3 minutes. + /// + /// + public bool ShouldRecycle() + { + if (_testCaseExecutionCount >= RecycleCount) + { + return true; + } + if (LastUsedTime.Elapsed > s_inactivityPeriod) + { + return true; + } + return false; + } + + public bool IsRunning => (_process != null) && !_process.HasExited; + } +} diff --git a/Antigen/Execution/ExecuteResult.cs b/Antigen/Execution/ExecuteResult.cs new file mode 100644 index 0000000..849004b --- /dev/null +++ b/Antigen/Execution/ExecuteResult.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Linq; +using System.Text; +using System.Threading.Tasks; +using Utils; + +namespace Antigen.Execution +{ + public enum RunOutcome + { + Success, + Timeout, + AssertionFailure, + OutputMismatch, + OtherError, + CompilationError, + } + + internal struct ExecuteResult + { + internal string OtherErrorMessage { get; private set; } + internal string AssertionMessage { get; private set; } + internal string ShortAssertionText { get; private set; } + internal RunOutcome Result { get; private set; } + internal IReadOnlyList> EnvVars { get; private set; } + + internal static ExecuteResult GetSuccessResult() + { + return new ExecuteResult(RunOutcome.Success, null); + } + + internal static ExecuteResult GetOtherErrorResult(string errorMessage, IReadOnlyList> envVars) + { + return new ExecuteResult(RunOutcome.OtherError, null, errorMessage, envVars); + } + + internal static ExecuteResult GetTimeoutResult() + { + return new ExecuteResult(RunOutcome.Timeout, null); + } + + internal static ExecuteResult GetAssertionFailureResult(string assertionMessage, IReadOnlyList> envVars) + { + var result = new ExecuteResult(RunOutcome.AssertionFailure, assertionMessage, null, envVars); + result.ShortAssertionText = RslnUtilities.ParseAssertionError(assertionMessage); + return result; + } + + internal static ExecuteResult GetOutputMismatchResult(string outputDiff, IReadOnlyList> envVars) + { + return new ExecuteResult(RunOutcome.OutputMismatch, null, outputDiff, envVars); + } + + internal static ExecuteResult GetCompilationError() + { + return new ExecuteResult(RunOutcome.CompilationError, null); + } + + private ExecuteResult(RunOutcome result, string assertionMessage, string errorMessage = null, IReadOnlyList> envVars = null) + { + Result = result; + AssertionMessage = assertionMessage; + OtherErrorMessage = errorMessage; + EnvVars = envVars; + } + + } +} diff --git a/Antigen/Helpers/PreGenerated.cs b/Antigen/Helpers/PreGenerated.cs index c69a14e..74e3602 100644 --- a/Antigen/Helpers/PreGenerated.cs +++ b/Antigen/Helpers/PreGenerated.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; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using Antigen.Statements; @@ -66,8 +68,14 @@ public static Statement StaticMethods // Main method staticMethodBuilder.AppendLine("public static void Main(string[] args) { "); + //staticMethodBuilder.AppendLine($"new {MainClassName}().Method0();"); + //staticMethodBuilder.AppendLine("PrintLog();"); + staticMethodBuilder.AppendLine("Antigen();"); + staticMethodBuilder.AppendLine("}"); + + staticMethodBuilder.AppendLine("public static int Antigen() { "); staticMethodBuilder.AppendLine($"new {MainClassName}().Method0();"); - staticMethodBuilder.AppendLine("PrintLog();"); + staticMethodBuilder.AppendLine("return string.Join(Environment.NewLine, toPrint).GetHashCode();"); staticMethodBuilder.AppendLine("}"); // Log method diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index aad37cf..77717e3 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -140,51 +140,55 @@ private static void RecordVectorTypes() public static void RecordVectorMethods() { - lock (Program.s_spinLock) + Debug.Assert(s_allVectorTypes == null); + + if (s_allVectorTypes != null) { - RecordVectorTypes(); - - s_allVectorMethods = new List(); - - RecordIntrinsicMethods(typeof(Vector)); - RecordIntrinsicMethods(typeof(Vector2)); - RecordIntrinsicMethods(typeof(Vector3)); - RecordIntrinsicMethods(typeof(Vector4)); - RecordVectorCtors(typeof(Vector2)); - RecordVectorCtors(typeof(Vector3)); - RecordVectorCtors(typeof(Vector4)); - RecordIntrinsicMethods(typeof(Vector64)); - RecordIntrinsicMethods(typeof(Vector128)); - RecordIntrinsicMethods(typeof(Vector256)); - RecordIntrinsicMethods(typeof(Vector512)); - RecordIntrinsicMethods(typeof(AdvSimd)); - RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); - RecordIntrinsicMethods(typeof(Sve)); - RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); - RecordIntrinsicMethods(typeof(Bmi1)); - RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); - RecordIntrinsicMethods(typeof(Bmi2)); - RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); - RecordIntrinsicMethods(typeof(Fma)); - RecordIntrinsicMethods(typeof(Lzcnt)); - RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); - RecordIntrinsicMethods(typeof(Pclmulqdq)); - RecordIntrinsicMethods(typeof(Popcnt)); - RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); - RecordIntrinsicMethods(typeof(Avx)); - RecordIntrinsicMethods(typeof(Avx2)); - RecordIntrinsicMethods(typeof(Avx512BW)); - RecordIntrinsicMethods(typeof(Avx512CD)); - RecordIntrinsicMethods(typeof(Avx512DQ)); - RecordIntrinsicMethods(typeof(Avx512F)); - RecordIntrinsicMethods(typeof(Avx512Vbmi)); - RecordIntrinsicMethods(typeof(Sse)); - RecordIntrinsicMethods(typeof(Sse2)); - RecordIntrinsicMethods(typeof(Sse3)); - RecordIntrinsicMethods(typeof(Sse41)); - RecordIntrinsicMethods(typeof(Sse42)); - RecordIntrinsicMethods(typeof(Sse)); + return; } + + RecordVectorTypes(); + + s_allVectorMethods = new List(); + + RecordIntrinsicMethods(typeof(Vector)); + RecordIntrinsicMethods(typeof(Vector2)); + RecordIntrinsicMethods(typeof(Vector3)); + RecordIntrinsicMethods(typeof(Vector4)); + RecordVectorCtors(typeof(Vector2)); + RecordVectorCtors(typeof(Vector3)); + RecordVectorCtors(typeof(Vector4)); + RecordIntrinsicMethods(typeof(Vector64)); + RecordIntrinsicMethods(typeof(Vector128)); + RecordIntrinsicMethods(typeof(Vector256)); + RecordIntrinsicMethods(typeof(Vector512)); + RecordIntrinsicMethods(typeof(AdvSimd)); + RecordIntrinsicMethods(typeof(AdvSimd.Arm64), "AdvSimd.Arm64"); + RecordIntrinsicMethods(typeof(Sve)); + RecordIntrinsicMethods(typeof(System.Runtime.Intrinsics.X86.Aes)); + RecordIntrinsicMethods(typeof(Bmi1)); + RecordIntrinsicMethods(typeof(Bmi1.X64), "Bmi1.X64"); + RecordIntrinsicMethods(typeof(Bmi2)); + RecordIntrinsicMethods(typeof(Bmi2.X64), "Bmi2.X64"); + RecordIntrinsicMethods(typeof(Fma)); + RecordIntrinsicMethods(typeof(Lzcnt)); + RecordIntrinsicMethods(typeof(Lzcnt.X64), "Lzcnt.X64"); + RecordIntrinsicMethods(typeof(Pclmulqdq)); + RecordIntrinsicMethods(typeof(Popcnt)); + RecordIntrinsicMethods(typeof(Popcnt.X64), "Popcnt.X64"); + RecordIntrinsicMethods(typeof(Avx)); + RecordIntrinsicMethods(typeof(Avx2)); + RecordIntrinsicMethods(typeof(Avx512BW)); + RecordIntrinsicMethods(typeof(Avx512CD)); + RecordIntrinsicMethods(typeof(Avx512DQ)); + RecordIntrinsicMethods(typeof(Avx512F)); + RecordIntrinsicMethods(typeof(Avx512Vbmi)); + RecordIntrinsicMethods(typeof(Sse)); + RecordIntrinsicMethods(typeof(Sse2)); + RecordIntrinsicMethods(typeof(Sse3)); + RecordIntrinsicMethods(typeof(Sse41)); + RecordIntrinsicMethods(typeof(Sse42)); + RecordIntrinsicMethods(typeof(Sse)); } private static bool ShouldSkipVectorMethod(string fullMethodName) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 42051d0..29c8036 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -11,10 +11,14 @@ using System.Text; using System.Threading; using Utils; +using Antigen.Compilation; +using Antigen.Execution; +using static System.Net.Mime.MediaTypeNames; +using System.Reflection; namespace Antigen { - public class TestCase + public class TestCase : IDisposable { #region Compiler options @@ -28,14 +32,17 @@ public enum CompilationType private readonly List _knownDiffs = new List() { "System.OverflowException: Value was either too large or too small for a Decimal.", + "Value was either too large or too small for a Decimal.", "System.DivideByZeroException: Attempted to divide by zero.", + "Attempted to divide by zero.", + "Arithmetic operation resulted in an overflow.", "isCandidateVar(fieldVarDsc) == isMultiReg", // https://github.com/dotnet/runtime/issues/85628 "curSize < maxSplitSize", // https://github.com/dotnet/runtime/issues/91251 }; private SyntaxNode testCaseRoot; - private struct UniqueIssueFile + private class UniqueIssueFile { public readonly int UniqueIssueId; public readonly int FileSize; @@ -74,8 +81,11 @@ public void IncreaseHitCount() new Weights(int.MaxValue, (double) PRNG.Next(1, 10) / 10000 ), }; - private static TestRunner s_testRunner; - private static RunOptions s_runOptions; + internal static EEDriver s_Driver = null; + internal static TestRunner s_TestRunner = null; + internal static RunOptions s_RunOptions = null; + + private Compiler m_compiler { get; set; } internal ConfigOptions Config { get; private set; } public string Name { get; private set; } @@ -84,8 +94,7 @@ public void IncreaseHitCount() public TestCase(int testId, RunOptions runOptions) { - s_runOptions = runOptions; - Config = s_runOptions.Configs[PRNG.Next(s_runOptions.Configs.Count)]; + Config = s_RunOptions.Configs[PRNG.Next(s_RunOptions.Configs.Count)]; ContainsVectorData = PRNG.Decide(Config.VectorDataProbability); if (RuntimeInformation.OSArchitecture == Architecture.X64) @@ -105,7 +114,8 @@ public TestCase(int testId, RunOptions runOptions) AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; - s_testRunner = TestRunner.GetInstance(s_runOptions.CoreRun, s_runOptions.OutputDirectory); + + m_compiler = new Compiler(s_RunOptions.OutputDirectory); } public void Generate() @@ -118,151 +128,98 @@ public void Generate() public TestResult Verify() { SyntaxTree syntaxTree = testCaseRoot.SyntaxTree; // RslnUtilities.GetValidSyntaxTree(testCaseRoot); + CompileResult compileResult = m_compiler.Compile(syntaxTree, Name); + ExecuteResult executeResult = s_TestRunner.Execute(compileResult); - CompileResult compileResult = s_testRunner.Compile(syntaxTree, Name); - if (compileResult.AssemblyFullPath == null) + switch(executeResult.Result) { -#if UNREACHABLE - StringBuilder fileContents = new StringBuilder(); - - fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().ToFullString()); - fileContents.AppendLine("/*"); - fileContents.AppendLine($"Got {compileResult.CompileErrors.Count()} compiler error(s):"); - foreach (var error in compileResult.CompileErrors) + case RunOutcome.CompilationError: + return TestResult.CompileError; + case RunOutcome.AssertionFailure: { - fileContents.AppendLine(error.ToString()); - } - fileContents.AppendLine("*/"); - - string errorFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-compile-error.g.cs"); - File.WriteAllText(errorFile, fileContents.ToString()); -#endif - return compileResult.RoslynException != null ? TestResult.RoslynException : TestResult.CompileError; - } -#if UNREACHABLE - else - { - string workingFile = Path.Combine(s_runOptions.OutputDirectory, $"{Name}-working.g.cs"); - File.WriteAllText(workingFile, testCaseRoot.ToFullString()); - } -#endif - bool isx64 = RuntimeInformation.OSArchitecture == Architecture.X64; - var baselineVariables = EnvVarOptions.BaseLineVars(Config.UseSve && isx64); - var testVariables = EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), Config.UseSve && isx64); - - // Execute test first and see if we have any errors/asserts - var test = s_testRunner.Execute(compileResult, testVariables); - - // If timeout, skip - if (test == "TIMEOUT") - { - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); - } - - // If OOM, skip - else if (test.Contains("Out of memory")) - { -#if UNREACHABLE - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-oom"); + var assertionMessage = executeResult.AssertionMessage; + var parsedAssertion = executeResult.ShortAssertionText; -#endif - return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); - } - - var testAssertion = RslnUtilities.ParseAssertionError(test); - - // If test assertion - if (!string.IsNullOrEmpty(testAssertion)) - { - foreach (var knownError in _knownDiffs) - { - if (testAssertion.Contains(knownError)) + if (!string.IsNullOrEmpty(parsedAssertion)) + { + foreach (var knownError in _knownDiffs) + { + if (parsedAssertion.Contains(knownError)) + { + return TestResult.Pass; + } + } + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, executeResult.AssertionMessage, executeResult.EnvVars, parsedAssertion, $"{Name}-test-assertion"); + return TestResult.Assertion; + } + else { - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); + foreach (var knownError in _knownDiffs) + { + if (assertionMessage.Contains(knownError)) + { + //SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-divbyzero"); + + return assertionMessage.Contains("System.OverflowException:") ? TestResult.Overflow : TestResult.DivideByZero; + } + } } + return TestResult.Assertion; } - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, testAssertion, $"{Name}-test-assertion"); - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); - } - else - { - foreach (string knownError in _knownDiffs) + case RunOutcome.OtherError: { - if (test.Contains(knownError)) + string errorMessage = executeResult.OtherErrorMessage; + if (errorMessage.Contains("System.OutOfMemoryException")) { - //SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, null, null, test, testVariables, "Out of memory", $"{Name}-test-divbyzero"); - - return TheTestResult(compileResult.AssemblyFullPath, test.Contains("System.OverflowException:") ? TestResult.Overflow : TestResult.DivideByZero); + return TestResult.OOM; } - } - } - - if (!PRNG.Decide(s_runOptions.ExecuteBaseline)) - { - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); - } - - string baseline = s_testRunner.Execute(compileResult, baselineVariables); - - // If timeout, skip - if (baseline == "TIMEOUT" || string.IsNullOrEmpty(baseline) || string.IsNullOrEmpty(test)) - { - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); - } - - // If OOM, ignore this diff - else if (baseline.Contains("Out of memory")) - { -#if UNREACHABLE - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, "Out of memory", $"{Name}-base-oom"); ; -#endif - return TheTestResult(compileResult.AssemblyFullPath, TestResult.OOM); - } + if (errorMessage == "Operation is not supported on this platform.") + { + // probably we are running with Altjit. - string baselineAssertion = RslnUtilities.ParseAssertionError(baseline); + return TestResult.Pass; + } + foreach (var knownError in _knownDiffs) + { + if (errorMessage.Contains(knownError)) + { + if (errorMessage.Contains("Attempted to divide by zero")) + { + return TestResult.DivideByZero; + } + else if (errorMessage.Contains("overflow") || errorMessage.Contains("too large or too small")) + { + return TestResult.Overflow; + } + } + return TestResult.OtherError; + } + var parsedError = RslnUtilities.ParseAssertionError(errorMessage); + parsedError = parsedError ?? errorMessage; - // Is there assertion in baseline? - if (!string.IsNullOrEmpty(baselineAssertion)) - { - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, null, null, baselineAssertion, $"{Name}-base-assertion"); - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Assertion); - } - // If baseline and test output doesn't match - else if (baseline != test) - { - var unsupportedOperationInBaseline = baseline.Contains("System.PlatformNotSupportedException"); - var unsupportedOperationInTest = test.Contains("System.PlatformNotSupportedException"); - if (unsupportedOperationInBaseline == unsupportedOperationInTest) + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, executeResult.OtherErrorMessage, executeResult.EnvVars, parsedError, $"{Name}-test-error"); + return TestResult.OtherError; + } + case RunOutcome.OutputMismatch: { - // Only return mismatch output if both baseline/test contains "not supported" or both doesn't contain this exception. - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, baseline, baselineVariables, test, testVariables, "OutputMismatch", $"{Name}-output-mismatch"); - return TheTestResult(compileResult.AssemblyFullPath, TestResult.OutputMismatch); + var outputDiff = executeResult.OtherErrorMessage; + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, outputDiff, executeResult.EnvVars, outputDiff, $"{Name}-test-output-mismatch"); + return TestResult.OutputMismatch; } + case RunOutcome.Timeout: + { + return TestResult.Timeout; + } + default: + return TestResult.Pass; } - - return TheTestResult(compileResult.AssemblyFullPath, TestResult.Pass); - } - - private TestResult TheTestResult(string assemblyPath, TestResult result) - { - try - { - File.Delete(assemblyPath); - } - catch - { - // ignore errors - } - return result; } private void SaveTestCase( string assemblyPath, SyntaxNode testCaseRoot, - string baselineOutput, - Dictionary baselineVars, string testOutput, - Dictionary testVars, + IReadOnlyList> envVars, string failureText, string testFileName) { @@ -271,42 +228,23 @@ private void SaveTestCase( #endif StringBuilder fileContents = new StringBuilder(); - if (baselineVars != null) + if (envVars != null) { - fileContents.AppendLine($"// BaselineVars: {string.Join("|", baselineVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); - } - if (testVars != null) - { - fileContents.AppendLine($"// TestVars: {string.Join("|", testVars.ToList().Select(x => $"{x.Key}={x.Value}"))}"); + fileContents.AppendLine($"// EnvVars: {string.Join("|", envVars.ToList().Select(x => $"{x.Item1}={x.Item2}"))}"); } fileContents.AppendLine("//"); fileContents.AppendLine(testCaseRoot.NormalizeWhitespace().SyntaxTree.GetText().ToString()); fileContents.AppendLine("/*"); fileContents.AppendFormat("Config: {0}", Config.Name).AppendLine(); - fileContents.AppendLine("--------- Baseline ---------"); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - if (baselineVars != null) - { - foreach (var envVars in baselineVars) - { - fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); - } - } - fileContents.AppendLine(); - fileContents.AppendLine(baselineOutput); - - fileContents.AppendLine("--------- Test ---------"); fileContents.AppendLine(); fileContents.AppendLine("Environment:"); fileContents.AppendLine(); - if (testVars != null) + if (envVars != null) { - foreach (var envVars in testVars) + foreach (var envVar in envVars) { - fileContents.AppendFormat("{0}={1}", envVars.Key, envVars.Value).AppendLine(); + fileContents.AppendFormat("{0}={1}", envVar.Item1, envVar.Item2).AppendLine(); } } fileContents.AppendLine(); @@ -317,8 +255,7 @@ private void SaveTestCase( fileContents.AppendLine(failureText); fileContents.AppendLine("*/"); - string output = string.IsNullOrEmpty(baselineOutput) ? testOutput : baselineOutput; - StringBuilder summaryContents = new StringBuilder(output); + StringBuilder summaryContents = new StringBuilder(testOutput); string uniqueIssueDirName = null; int assertionHashCode = failureText.GetHashCode(); string currentReproFile = $"{testFileName}.g.cs"; @@ -340,7 +277,7 @@ private void SaveTestCase( // Create hash of testAssertion and copy files in respective bucket. - uniqueIssueDirName = Path.Combine(s_runOptions.OutputDirectory, $"UniqueIssue{uniqueIssueFile.UniqueIssueId}"); + uniqueIssueDirName = Path.Combine(s_RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssueFile.UniqueIssueId}"); if (!Directory.Exists(uniqueIssueDirName)) { @@ -368,5 +305,11 @@ private void SaveTestCase( } } + public void Dispose() + { + this.testCaseRoot = null; + this.m_compiler = null; + GC.Collect(); + } } } diff --git a/ExecutionEngine/DynamicAssemblyLoader.cs b/ExecutionEngine/DynamicAssemblyLoader.cs new file mode 100644 index 0000000..739ae46 --- /dev/null +++ b/ExecutionEngine/DynamicAssemblyLoader.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.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; + +namespace ExecutionEngine +{ + public class DynamicAssemblyLoader : AssemblyLoadContext + { + public DynamicAssemblyLoader() : base(isCollectible: true) { } + + public Assembly LoadFromBytes(byte[] assemblyBytes) + { + return LoadFromStream(new MemoryStream(assemblyBytes)); + } + + protected override Assembly Load(AssemblyName assemblyName) + { + // Default implementation does nothing. + return null; + } + } +} diff --git a/ExecutionEngine/ExecutionEngine.csproj b/ExecutionEngine/ExecutionEngine.csproj new file mode 100644 index 0000000..f28cb55 --- /dev/null +++ b/ExecutionEngine/ExecutionEngine.csproj @@ -0,0 +1,18 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + diff --git a/ExecutionEngine/Program.cs b/ExecutionEngine/Program.cs new file mode 100644 index 0000000..b0a58f3 --- /dev/null +++ b/ExecutionEngine/Program.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.Diagnostics; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.ExceptionServices; +using System.Threading; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace ExecutionEngine +{ + internal class Program + { + private static DynamicAssemblyLoader s_loader = new(); + private static int s_parentProcessId; + private const int ALCRecycleCount = 100; + + static async Task Main(string[] args) + { + if (args.Length != 1) + { + throw new ArgumentException("Expected exactly one argument"); + } + + s_parentProcessId = int.Parse(args[0]); + + // Start a background thread to monitor the parent process + Task monitorTask = Task.Run(() => MonitorParentProcess()); + int currentAlcCount = 0; + while (true) + { + var lines = Console.ReadLine(); + if (lines == null) + { + continue; + } + Request? request = JsonConvert.DeserializeObject(lines); + if (request == null) + { + continue; + } + + RunResult debugResult = Run(request.Debug); + RunResult releaseResult = Run(request.Release); + + + Response response = new Response() + { + DebugOutput = debugResult.HashCode, + DebugError = debugResult.Error, + ReleaseOutput = releaseResult.HashCode, + ReleaseError = releaseResult.Error + }; + + if (debugResult.IsJitAssert || releaseResult.IsJitAssert) + { + response.IsJitAssert = true; + } + + var json = JsonConvert.SerializeObject(response); + Console.WriteLine(json); + Console.Out.Flush(); + Console.WriteLine("Done"); + Console.Out.Flush(); + + currentAlcCount++; + if (currentAlcCount > ALCRecycleCount) + { + s_loader = new DynamicAssemblyLoader(); + currentAlcCount = 0; + } + } + } + + /// + /// Run the assmebly and return the hash code + /// + /// + /// + /// + private static RunResult Run(byte[] assemblyBytes) + { + int hashCode; + var assembly = s_loader.LoadFromBytes(assemblyBytes); + var methodInfo = assembly.GetType("TestClass").GetMethod("Antigen"); + var methodExec = methodInfo.CreateDelegate>(); + + // Adopted from Jakob's Fuzzlyn + int threadID = Environment.CurrentManagedThreadId; + List exceptions = null; + void FirstChanceExceptionHandler(object sender, FirstChanceExceptionEventArgs args) + { + if (Environment.CurrentManagedThreadId == threadID) + { + (exceptions ??= new List()).Add(args.Exception); + } + } + + AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionHandler; + + try + { + hashCode = methodExec(); + } + catch + { + // We consider the innermost exception the root cause and only report it. + // Otherwise we may be confusing the viewer about what the problem is. + // Consider for example (adapted from a real example): + // try + // { + // value = -1; + // FunctionThatJitAssertsInDebug(); + // value = 1; + // } + // finally + // { + // int.MinValue / value; + // } + // We are interested in the JIT assert that was hit, and not the OverflowException + // thrown because value = 1 did not get to run. + Exception ex = exceptions[0]; + + if (ex is TypeInitializationException && ex.InnerException != null) + { + ex = ex.InnerException; + } + + if (ex is InvalidProgramException && ex.Message.Contains("JIT assert failed")) + { + return RunResult.JitAssertionResult(ex.Message); + } + + return RunResult.ErrorResult(ex.Message); + } + finally + { + AppDomain.CurrentDomain.FirstChanceException -= FirstChanceExceptionHandler; + } + + return RunResult.SuccessResult(hashCode); + } + + /// + /// Monitor parent process every 10 seconds and exit if it terminates + /// + private static void MonitorParentProcess() + { + try + { + while (true) + { + // Check if the parent process is still running + Process.GetProcessById(s_parentProcessId); + Thread.Sleep(10000); // Check every 10 seconds + } + } + catch (ArgumentException) + { + // Parent process is no longer running + Console.WriteLine("Parent process terminated. Exiting..."); + Environment.Exit(0); + } + } + } +} diff --git a/ExecutionEngine/RequestResponse.cs b/ExecutionEngine/RequestResponse.cs new file mode 100644 index 0000000..598bb6b --- /dev/null +++ b/ExecutionEngine/RequestResponse.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.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ExecutionEngine +{ + public class Request + { + public byte[] Debug { get; set; } + public byte[] Release { get; set; } + } + + public class Response + { + public int DebugOutput { get; set; } + public string? DebugError { get; set; } + public int ReleaseOutput { get; set; } + public string? ReleaseError { get; set; } + public bool IsTimeout { get; set; } + public bool IsJitAssert { get; set; } + public bool HasCrashed { get; set; } + public IReadOnlyList> EnvironmentVariables { get; set; } + } +} diff --git a/ExecutionEngine/RunResult.cs b/ExecutionEngine/RunResult.cs new file mode 100644 index 0000000..eadc453 --- /dev/null +++ b/ExecutionEngine/RunResult.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ExecutionEngine +{ + internal struct RunResult + { + public int HashCode { get; private set; } + public string? Error { get; private set; } + public bool IsTimeout { get; private set; } + public bool IsJitAssert { get; private set; } + + private RunResult(int hashCode, string? error, bool isTimeout, bool isJitAssert) + { + HashCode = hashCode; + Error = error; + IsTimeout = isTimeout; + IsJitAssert = isJitAssert; + } + + internal static RunResult SuccessResult(int hashCode) => new RunResult(hashCode, null, false, false); + internal static RunResult ErrorResult(string error) => new RunResult(0, error, false, false); + internal static RunResult TimeoutResult() => new RunResult(0, null, true, false); + internal static RunResult JitAssertionResult(string error) => new RunResult(0, error, true, true); + } +} diff --git a/README.md b/README.md index 7448a76..d37591e 100644 --- a/README.md +++ b/README.md @@ -127,4 +127,8 @@ Antigen also comes with a component called `Trimmer` which would trim the C# cod ## Are there any other fuzzers? -There are lot of fuzzers to test compilers. One of them is [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) developed by [Jakob Botsch Nielsen](https://jakobbotsch.com/). \ No newline at end of file +There are lot of fuzzers to test compilers. One of them is [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) developed by [Jakob Botsch Nielsen](https://jakobbotsch.com/). + +## Credits + +The design idea of running an execution server that speed up the runtime of Antigen tests was adopted from [Fuzzlyn](https://github.com/jakobbotsch/Fuzzlyn) developed by [Jakob Botsch Nielsen](https://jakobbotsch.com/). \ No newline at end of file diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index a7b1129..ef810a0 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.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 Antigen.Compilation; +using Antigen.Execution; using Antigen.Trimmer.Rewriters; using Antigen.Trimmer.Rewriters.Expressions; using Antigen.Trimmer.Rewriters.Statements; @@ -12,6 +14,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -19,17 +23,25 @@ namespace Trimmer { + public struct ReproDetails + { + public Dictionary envVars; + public TestResult failureKind; + public string assertionText; + } + public class TestTrimmer { - private string _testFileToTrim; + private SyntaxNode _treeToTrim; + private ExecuteResult _lkgExecuteResult; private int _sizeOfTestFileToTrim; private static TestRunner _testRunner; - private Dictionary _baselineVariables; - private Dictionary _testVariables; - private string _originalTestAssertion; - static int s_iterId = 1; + private int _iterId = 0; static int TRIMMER_RESET_COUNT = 10; - private CommandLineOptions _opts = null; + private readonly CommandLineOptions _opts = null; + private readonly Compiler _compiler; + private readonly ReproDetails _reproDetails; + private readonly string _issueFolder; static int Main(string[] args) { @@ -41,6 +53,7 @@ private static int Run(CommandLineOptions opts) string testCaseToTrim = opts.ReproFile; TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, opts); testTrimmer.Trim(); + testTrimmer.SaveRepro(); return 0; } @@ -50,55 +63,83 @@ public TestTrimmer(string testFileToTrim, CommandLineOptions opts) { throw new Exception($"{testFileToTrim} doesn't exist."); } - _testFileToTrim = testFileToTrim; - _sizeOfTestFileToTrim = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot().ToFullString().Length; + _issueFolder = opts.IssuesFolder; _opts = opts; - _testRunner = TestRunner.GetInstance(opts.CoreRunPath, opts.IssuesFolder); + _compiler = new Compiler(opts.IssuesFolder); - ParseEnvironment(); + _reproDetails = ParseReproFile(testFileToTrim); + EEDriver driver = EEDriver.GetInstance(opts.CoreRunPath, + Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), + () => _reproDetails.envVars); + + _testRunner = TestRunner.GetInstance(driver, opts.CoreRunPath, opts.IssuesFolder); } /// /// Returns a tuple of Baseline, Test environment variables /// /// - private void ParseEnvironment() + private ReproDetails ParseReproFile(string testFileToTrim) { - var fileContents = File.ReadAllText(_testFileToTrim.Replace(Environment.NewLine, "\n")); - string[] fileContentLines = fileContents.Split("\n"); - _originalTestAssertion = RslnUtilities.ParseAssertionError(fileContents); + var reproDetails = new ReproDetails(); + + var fileContents = File.ReadAllText(testFileToTrim); + _treeToTrim = CSharpSyntaxTree.ParseText(fileContents).GetRoot(); + _sizeOfTestFileToTrim = _treeToTrim.ToFullString().Length; + + fileContents = fileContents.Replace(Environment.NewLine, "\n"); + var fileContentLines = fileContents.Split("\n"); foreach (var line in fileContentLines) { var lineContent = line.Trim(); - if (lineContent.StartsWith("// BaselineVars: ")) - { - var baselineContents = lineContent.Replace("// BaselineVars: ", string.Empty).Trim(); - _baselineVariables = baselineContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); - continue; - } - else if (lineContent.StartsWith("// TestVars: ")) + if (lineContent.StartsWith("// EnvVars: ")) { - var testContents = lineContent.Replace("// TestVars: ", string.Empty).Trim(); - _testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); + var testContents = lineContent.Replace("// EnvVars: ", string.Empty).Trim(); + var testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); if (!string.IsNullOrEmpty(_opts.AltJitName)) { - _testVariables["DOTNET_AltJitName"] = _opts.AltJitName; + testVariables["DOTNET_AltJitName"] = _opts.AltJitName; } if (!string.IsNullOrEmpty(_opts.AltJitMethodName)) { - _testVariables["DOTNET_AltJit"] = _opts.AltJitMethodName; + testVariables["DOTNET_AltJit"] = _opts.AltJitMethodName; } - return; + reproDetails.envVars = testVariables; + break; } - throw new Exception("Baseline/TestVars not present."); + throw new Exception("EnvVars not present."); + } + + string assertionMessage = RslnUtilities.ParseAssertionError(fileContents); + if (!string.IsNullOrEmpty(assertionMessage)) + { + reproDetails.assertionText = assertionMessage; + reproDetails.failureKind = TestResult.Assertion; + return reproDetails; + } + + int debugCode = 0, releaseCode = 0; + for (var i = fileContentLines.Length - 1; i >= 0; i--) + { + var line = fileContentLines[i].Trim(); + if (line.StartsWith("Debug: ")) + { + debugCode = int.Parse(line.Replace("Debug: ", string.Empty)); + break; + } + else if (line.StartsWith("Release: ")) + { + releaseCode = int.Parse(line.Replace("Release: ", string.Empty)); + } } - //throw new Exception("Baseline/TestVars not present."); - //return null; + + reproDetails.failureKind = debugCode != releaseCode ? TestResult.OutputMismatch : TestResult.Pass; + return reproDetails; } public void Trim() @@ -118,7 +159,7 @@ public void TrimTree() do { trimmedAtleastOne = false; - trimmedAtleastOne |= TrimEnvVars(); + //trimmedAtleastOne |= TrimEnvVars(); trimmedAtleastOne |= TrimStatements(); trimmedAtleastOne |= TrimExpressions(); @@ -203,53 +244,23 @@ public bool TrimExpressions() return trimmedAtleastOne; } - public bool TrimEnvVars() - { - bool trimmedAtleastOne = false; - SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); - var keys = _testVariables.Keys.ToList(); - - foreach (var envVar in keys) - { - if (envVar.Contains("AltJit")) - { - continue; - } - string value = _testVariables[envVar]; - - _testVariables.Remove(envVar); - Console.Write($"{s_iterId}. Removing {envVar}={value}"); - if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) == TestResult.Pass) - { - Console.WriteLine(" - Revert"); - _testVariables[envVar] = value; - } - else - { - Console.WriteLine(" - Success"); - trimmedAtleastOne = true; - } - } - - return trimmedAtleastOne; - } - /// /// Trim the test case. /// private bool Trim(List trimmerList) { - SyntaxNode recentTree = CSharpSyntaxTree.ParseText(File.ReadAllText(_testFileToTrim)).GetRoot(); - CompileResult compileResult = _testRunner.Compile(recentTree.SyntaxTree, "base"); - if (compileResult.AssemblyName == null) + SyntaxNode recentTree = _treeToTrim; + CompileResult compileResult = _compiler.Compile(recentTree.SyntaxTree, "trimmer"); + ExecuteResult executeResult = _testRunner.Execute(compileResult); + + if (executeResult.Result == RunOutcome.CompilationError) { return false; } bool trimmedAtleastOne = false; bool trimmedInCurrIter; - TestResult expectedResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; - if (Verify($"trim{s_iterId++}", recentTree, _baselineVariables, _testVariables) != expectedResult) + if (Verify($"trim{_iterId++}", recentTree) != _reproDetails.failureKind) { return false; } @@ -268,7 +279,7 @@ private bool Trim(List trimmerList) SyntaxNode treeBeforeTrim = recentTree, treeAfterTrim = null; // remove all - Console.Write($"{s_iterId}. {trimmer.GetType()}"); + Console.Write($"{_iterId}. {trimmer.GetType()}"); int noOfNodes = 0; bool gotException = false; @@ -307,7 +318,7 @@ private bool Trim(List trimmerList) if (!gotException && !isSameTree && // If they are same tree trimmer.IsAnyNodeVisited && // We have visited and removed at least one node - Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == expectedResult) + Verify($"trim{_iterId++}", treeAfterTrim) == _reproDetails.failureKind) { // move to next trimmer recentTree = treeAfterTrim; @@ -328,7 +339,7 @@ private bool Trim(List trimmerList) int localIterId = 0; while (nodeId < noOfNodes) { - Console.Write($"{s_iterId}. {trimmer.GetType()}, localIterId = {localIterId++}"); + Console.Write($"{_iterId}. {trimmer.GetType()}, localIterId = {localIterId++}"); trimmer.Reset(); trimmer.UpdateId(nodeId); @@ -355,7 +366,7 @@ private bool Trim(List trimmerList) if (!gotException && !isSameTree && trimmer.IsAnyNodeVisited && - Verify($"trim{s_iterId++}", treeAfterTrim, _baselineVariables, _testVariables) == expectedResult) + Verify($"trim{_iterId++}", treeAfterTrim) == _reproDetails.failureKind) { // move to next trimmer recentTree = treeAfterTrim; @@ -401,67 +412,49 @@ private bool Trim(List trimmerList) return trimmedAtleastOne; } - private List knownDiffs = new List() + private TestResult Verify(string iterId, SyntaxNode programRootNode/*, bool skipBaseline*/) { - "System.OverflowException: Value was either too large or too small for a Decimal.", - "System.DivideByZeroException: Attempted to divide by zero.", - }; + CompileResult compileResult = _compiler.Compile(programRootNode.SyntaxTree, iterId); + ExecuteResult executeResult = _testRunner.Execute(compileResult); - //TODO: refactor and merge with TestCase's Verify - private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary baselineEnvVars, Dictionary testEnvVars/*, bool skipBaseline*/) - { - bool hasAssertion = !string.IsNullOrEmpty(_originalTestAssertion); - CompileResult compileResult = _testRunner.Compile(programRootNode.SyntaxTree, iterId); - if (compileResult.AssemblyFullPath == null) + TestResult validationResult; + switch (executeResult.Result) { - return TestResult.CompileError; + case RunOutcome.CompilationError: + validationResult = TestResult.CompileError; + break; + case RunOutcome.AssertionFailure: + validationResult = _reproDetails.assertionText == executeResult.ShortAssertionText ? + TestResult.Pass : TestResult.Assertion; + break; + case RunOutcome.OutputMismatch: + validationResult = TestResult.OutputMismatch; + break; + case RunOutcome.Timeout: + case RunOutcome.Success: + validationResult = TestResult.Pass; + break; + default: + throw new Exception("Unknown outcome."); } - string currRunBaselineOutput = hasAssertion ? string.Empty : _testRunner.Execute(compileResult, null, 10); - string currRunTestOutput = _testRunner.Execute(compileResult, testEnvVars, 40); - - TestResult verificationResult = string.IsNullOrEmpty(_originalTestAssertion) ? TestResult.OutputMismatch : TestResult.Assertion; - - if (((currRunBaselineOutput == "TIMEOUT") && (currRunTestOutput == "TIMEOUT")) || - (currRunBaselineOutput == currRunTestOutput)) + if (_iterId % 100 == 0) { - // If output matches, then the test passes - verificationResult = TestResult.Pass; - } - else if (hasAssertion) - { - // Otherwise, if there was an assertion, verify that it is the same assertion - var currRunTestAssertion = RslnUtilities.ParseAssertionError(currRunTestOutput); - if (_originalTestAssertion != currRunTestAssertion) - { - // The assertion doesn't match. Consider this as PASS - verificationResult = TestResult.Pass; - } + SaveRepro(); } - foreach (string knownError in knownDiffs) + if ((validationResult == TestResult.Assertion) || (validationResult == TestResult.OutputMismatch)) { - if (currRunBaselineOutput.Contains(knownError) && currRunTestOutput.Contains(knownError)) - { - verificationResult = TestResult.Pass; - break; - } + _treeToTrim = programRootNode; + _lkgExecuteResult = executeResult; } - if (verificationResult == TestResult.Pass) - { - try - { - File.Delete(compileResult.AssemblyFullPath); - } - catch (Exception) - { - // ignore errors - } - return TestResult.Pass; - } + return validationResult; + } - string programContents = programRootNode.ToFullString(); + private void SaveRepro() + { + string programContents = _treeToTrim.ToFullString(); programContents = Regex.Replace(programContents, @"[\r\n]*$", string.Empty, RegexOptions.Multiline); StringBuilder fileContents = new StringBuilder(); @@ -470,44 +463,35 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode, Dictionary< fileContents.AppendLine(); fileContents.AppendLine(programContents); fileContents.AppendLine("/*"); - fileContents.AppendLine("Got output diff:"); - - fileContents.AppendLine("--------- Baseline --------- "); - fileContents.AppendLine(); fileContents.AppendLine("Environment:"); fileContents.AppendLine(); - if (baselineEnvVars != null) + if (_reproDetails.envVars != null) { - foreach (var envVars in baselineEnvVars) + foreach (var envVars in _reproDetails.envVars) { fileContents.AppendFormat("set {0}={1}", envVars.Key, envVars.Value).AppendLine(); } } fileContents.AppendLine(); - fileContents.AppendLine(currRunBaselineOutput); - - fileContents.AppendLine("--------- Test --------- "); - fileContents.AppendLine(); - fileContents.AppendLine("Environment:"); - fileContents.AppendLine(); - foreach (var envVars in testEnvVars) + if (_lkgExecuteResult.Result == RunOutcome.AssertionFailure) { - fileContents.AppendFormat("set {0}={1}", envVars.Key, envVars.Value).AppendLine(); + fileContents.AppendLine(_lkgExecuteResult.AssertionMessage); + } + else if (_lkgExecuteResult.Result == RunOutcome.OutputMismatch) + { + fileContents.AppendLine("Output mismatch."); + } + else if (_lkgExecuteResult.OtherErrorMessage != null) + { + fileContents.AppendLine(_lkgExecuteResult.OtherErrorMessage); } - fileContents.AppendLine(); - fileContents.AppendLine(currRunTestOutput); fileContents.AppendLine("*/"); //TODO: Only if something was visited string failedFileName = "repro-lkg"; - string failFile = Path.Combine(Path.GetDirectoryName(_testFileToTrim), $"{ failedFileName}.g.cs"); - //string failFile = Path.Combine(RunOptions.OutputDirectory, $"{failedFileName}.g.cs"); + string failFile = Path.Combine(_issueFolder, $"{failedFileName}.g.cs"); File.WriteAllText(failFile, fileContents.ToString()); - _testFileToTrim = failFile; - - File.Move(compileResult.AssemblyFullPath, Path.Combine(_opts.IssuesFolder, $"{failedFileName}.exe"), overwrite: true); - return verificationResult; } // Credits: https://stackoverflow.com/a/281679 diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index b1ead82..52ffa91 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -15,5 +15,17 @@ + + + + + + + + + + + + diff --git a/Utils/TestRunner.cs b/Utils/TestRunner.cs index e04bc65..af50ded 100644 --- a/Utils/TestRunner.cs +++ b/Utils/TestRunner.cs @@ -9,6 +9,9 @@ using System.Linq; using System.Reflection; using System.Text; +using Antigen.Compilation; +using Antigen.Execution; +using ExecutionEngine; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; @@ -23,18 +26,28 @@ public enum TestResult DivideByZero, OutputMismatch, Assertion, + OtherError, + Timeout, Pass, OOM } + public class TestRunner { - internal static readonly CSharpCompilationOptions CompileOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication, concurrentBuild: false, optimizationLevel: OptimizationLevel.Release/*, mainTypeName: "Main"*/); + internal static readonly CSharpCompilationOptions ReleaseCompileOptions = new ( + OutputKind.ConsoleApplication, + concurrentBuild: true, + optimizationLevel: OptimizationLevel.Release); + internal static readonly CSharpCompilationOptions DebugCompileOptions = new( + OutputKind.ConsoleApplication, + concurrentBuild: true, + optimizationLevel: OptimizationLevel.Debug); private static TestRunner _testRunner; - private static readonly bool s_useDotnet = false; private readonly string _coreRun; private readonly string _outputDirectory; + private readonly EEDriver _driver; private static readonly string s_corelibPath = typeof(object).Assembly.Location; private static readonly MetadataReference[] s_references = @@ -44,217 +57,77 @@ public class TestRunner MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(s_corelibPath), "System.Runtime.dll")), MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location), MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location), - }; + }; - private TestRunner(string coreRun, string outputFolder) + private TestRunner(EEDriver driver, string coreRun, string outputFolder) { _coreRun = coreRun; _outputDirectory = outputFolder; + _driver = driver; } - public static TestRunner GetInstance(string coreRun, string outputFolder) + internal static TestRunner GetInstance(EEDriver driver, string coreRun, string outputFolder) { if (_testRunner == null) { - _testRunner = new TestRunner(coreRun, outputFolder); + _testRunner = new TestRunner(driver, coreRun, outputFolder); } return _testRunner; } - /// - /// Compiles the generated . - /// - /// - internal CompileResult Compile(SyntaxTree programTree, string assemblyName) + internal ExecuteResult Execute(CompileResult compileResult) { - string assemblyFullPath = Path.Combine(_outputDirectory, $"{assemblyName}.exe"); - - var cc = CSharpCompilation.Create($"{assemblyName}.exe", new SyntaxTree[] { programTree }, s_references, CompileOptions); - - using (var ms = new MemoryStream()) + if (compileResult.DebugAssembly == null || compileResult.ReleaseAssembly == null) { - EmitResult result; - try - { - result = cc.Emit(ms); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - return new CompileResult(ex); - } - - if (!result.Success) - { -#if DEBUG - return new CompileResult(result.Diagnostics); -#else - return new CompileResult(null, null); -#endif - } - - ms.Seek(0, SeekOrigin.Begin); - File.WriteAllBytes(assemblyFullPath, ms.ToArray()); - //Console.WriteLine($"{ms.Length} bytes"); - - return new CompileResult(assemblyName, assemblyFullPath); + return ExecuteResult.GetCompilationError(); } - } - - /// - /// Execute the compiled assembly in an environment that has . - /// - /// - internal string Execute(CompileResult compileResult, Dictionary environmentVariables, int timeoutInSecs = 30) - { - Debug.Assert(compileResult.AssemblyFullPath != null); - - if (s_useDotnet) + var result = _driver.Execute(new() { - if (environmentVariables != null) - { - foreach (var envVar in environmentVariables) - { - Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); - } - } - - //TODO: if execute in debug vs. release dotnet.exe - Assembly asm = Assembly.LoadFrom(compileResult.AssemblyFullPath); - Type testClassType = asm.GetType(compileResult.AssemblyName); - MethodInfo mainMethodInfo = testClassType.GetMethod("Main"); - Action entryPoint = (Action)Delegate.CreateDelegate(typeof(Action), mainMethodInfo); - - Exception ex = null; - TextWriter origOut = Console.Out; - - MemoryStream ms = new MemoryStream(); - StreamWriter sw = new StreamWriter(ms, Encoding.UTF8); - - try - { - Console.SetOut(sw); - entryPoint(null); - } - catch (Exception caughtEx) - { - ex = caughtEx; - Console.WriteLine(caughtEx); - } - finally + Debug = compileResult.DebugAssembly, + Release = compileResult.ReleaseAssembly + }); + if (result == null) + { + // can't do much + return ExecuteResult.GetSuccessResult(); + } + else if (result.IsJitAssert) + { + return ExecuteResult.GetAssertionFailureResult(GetFailureOutput(result), result.EnvironmentVariables); + } + else if (result.IsTimeout) + { + return ExecuteResult.GetTimeoutResult(); + } + else if (!string.IsNullOrEmpty(result.DebugError) || !string.IsNullOrEmpty(result.ReleaseError)) + { + if (result.DebugError != result.ReleaseError) { - Console.SetOut(origOut); - sw.Close(); + return ExecuteResult.GetOutputMismatchResult(GetFailureOutput(result), result.EnvironmentVariables); } - - if (environmentVariables != null) + else { - foreach (var envVar in environmentVariables) - { - Environment.SetEnvironmentVariable(envVar.Key, null, EnvironmentVariableTarget.Process); - } + return ExecuteResult.GetOtherErrorResult(result.DebugError, result.EnvironmentVariables); } - - return Encoding.UTF8.GetString(ms.ToArray()); + } + else if (result.DebugOutput != result.ReleaseOutput) + { + return ExecuteResult.GetOutputMismatchResult(GetFailureOutput(result), result.EnvironmentVariables); } else { - ProcessStartInfo info = new ProcessStartInfo - { - FileName = _coreRun, - Arguments = compileResult.AssemblyFullPath, - WorkingDirectory = Environment.CurrentDirectory, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - }; - - if (environmentVariables != null) - { - foreach (var envVar in environmentVariables) - { - info.EnvironmentVariables[envVar.Key] = envVar.Value; - } - } - - using (Process proc = new Process()) - { - proc.StartInfo = info; - - bool started = proc.Start(); - if (!started) - { - throw new Exception("Process not started"); - } - - StringBuilder output = new StringBuilder(); - proc.OutputDataReceived += new DataReceivedEventHandler((s, e) => - { - if (!string.IsNullOrEmpty(e.Data)) - { - output.AppendLine(e.Data); - } - }); - - proc.ErrorDataReceived += new DataReceivedEventHandler((s, e) => - { - if (!string.IsNullOrEmpty(e.Data)) - { - output.AppendLine(e.Data); - } - }); - - proc.BeginOutputReadLine(); - proc.BeginErrorReadLine(); - - bool exited = proc.WaitForExit(timeoutInSecs * 1000); // 10 seconds - if (!exited) - { - try - { - proc.Kill(true); - } - catch { } - return "TIMEOUT"; - } - - string finalOutput = String.Empty; - try - { - finalOutput = output.ToString(); - - } catch (ArgumentOutOfRangeException) - { - } - return finalOutput.Trim(); - } + return ExecuteResult.GetSuccessResult(); } } - } - internal class CompileResult - { - public CompileResult(IEnumerable diagnostics) + internal string GetFailureOutput(Response response) { - CompileErrors = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Error); - CompileWarnings = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Warning); + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Debug: {response.DebugOutput}"); + sb.AppendLine(response.DebugError); + sb.AppendLine($"Release: {response.ReleaseOutput}"); + sb.AppendLine(response.ReleaseError); + return sb.ToString(); } - - public CompileResult(string assemblyName, string assemblyFullPath) - { - AssemblyName = assemblyName; - AssemblyFullPath = assemblyFullPath; - } - - public CompileResult(Exception roslynException) - { - RoslynException = roslynException; - } - - public string AssemblyName { get; } - public Exception RoslynException { get; } - public IEnumerable CompileErrors { get; } - public IEnumerable CompileWarnings { get; } - public string AssemblyFullPath { get; } } } From 9f1c2d2b8bd252a7414cd30cead0bbbc258bbe4a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 09:29:34 -0700 Subject: [PATCH 128/149] revert unintended commit --- ExecutionEngine/ExecutionEngine.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ExecutionEngine/ExecutionEngine.csproj b/ExecutionEngine/ExecutionEngine.csproj index f28cb55..88a4f80 100644 --- a/ExecutionEngine/ExecutionEngine.csproj +++ b/ExecutionEngine/ExecutionEngine.csproj @@ -11,8 +11,4 @@ - - - - From ff4825bda387821f432a9da08251a79f4b43afd7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 18:17:22 -0700 Subject: [PATCH 129/149] Remove MidPointRounding --- Antigen/Helpers/VectorHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Antigen/Helpers/VectorHelpers.cs b/Antigen/Helpers/VectorHelpers.cs index 77717e3..8f02186 100644 --- a/Antigen/Helpers/VectorHelpers.cs +++ b/Antigen/Helpers/VectorHelpers.cs @@ -201,7 +201,7 @@ private static bool ShouldSkipVectorMethod(string fullMethodName) fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") || /*fullMethodName.Contains("SveMaskPattern") ||*/ fullMethodName.Contains("SvePrefetchType") || fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("FloatRoundingMode") || - fullMethodName.Contains("Unsafe"); + fullMethodName.Contains("MidpointRounding") || fullMethodName.Contains("Unsafe"); } /// From 6b770423fc6dc93d32e9d8d3efae4e858bf41a44 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 19:58:05 -0700 Subject: [PATCH 130/149] Keep just switches that are verified in CI (#7) * Remove all the non-CI switches * Add all CI switches --- Antigen/Config/antigen.json | 268 +++++++++++------------------------- 1 file changed, 80 insertions(+), 188 deletions(-) diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index a964f1b..c15da70 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -30,14 +30,6 @@ "Name": "Default", "Weight": 0, "Variables": [ - { - "Name": "JitCloneLoops", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, { "Name": "JitAlignLoops", "Weight": 0.02, @@ -47,25 +39,7 @@ ] }, { - "Name": "JitAlignLoopAdaptive", - "Weight": 0.01, - "Values": [ - "1" - ] - }, - { - "Name": "JitAlignLoopMinBlockWeight", - "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "10", - "20" - ] - }, - { - "Name": "JitDoubleAlign", + "Name": "JitForceFallback", "Weight": 0.01, "Values": [ "0", @@ -73,7 +47,7 @@ ] }, { - "Name": "JitEnableDevirtualization", + "Name": "JitNoForceFallback", "Weight": 0.01, "Values": [ "0", @@ -81,58 +55,39 @@ ] }, { - "Name": "JitEnableLateDevirtualization", - "Weight": 0.01, + "Name": "JitSkipArrayBoundCheck", + "Weight": 0.0002, "Values": [ "0", "1" ] }, { - "Name": "JitForceFallback", - "Weight": 0.01, + "Name": "JitSlowDebugChecksEnabled", + "Weight": 0.002, "Values": [ "0", "1" ] }, { - "Name": "JITInlineDepth", + "Name": "JitStackChecks", "Weight": 0.01, - "Values": [ - "0", - "1", - "2", - "10", - "20" - ] - }, - { - "Name": "JitNoCMOV", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoCSE", - "Weight": 0.03, "Values": [ "0", "1" ] }, { - "Name": "JitNoCSE2", - "Weight": 0.05, + "Name": "InjectFault", + "Weight": 0.01, "Values": [ "0", "1" ] }, { - "Name": "JitNoForceFallback", + "Name": "JitEnableNoWayAssert", "Weight": 0.01, "Values": [ "0", @@ -140,7 +95,7 @@ ] }, { - "Name": "JitNoHoist", + "Name": "JitAggressiveInlining", "Weight": 0.05, "Values": [ "0", @@ -148,232 +103,171 @@ ] }, { - "Name": "JitNoInline", - "Weight": 0.04, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoMemoryBarriers", - "Weight": 0.02, - "Values": [ - "0", - "1" - ] - }, - { - "Name": "JitNoStructPromotion", - "Weight": 0.02, - "Values": [ - "0", - "1", - "2" - ] - }, - { - "Name": "JitNoUnroll", - "Weight": 0.02, + "Name": "JitOptRepeat", + "Weight": 0.0005, "Values": [ - "0", - "1" + "*" ] }, { - "Name": "JitStackAllocToLocalSize", - "Weight": 0.01, + "Name": "JitOptRepeatCount", + "Weight": 0.0003, "Values": [ - "0", - "1", "2", + "3", "4", - "10", - "16", - "100" + "5", + "6", + "10" ] }, { - "Name": "JitSkipArrayBoundCheck", - "Weight": 0.0002, + "Name": "JitStressEvexEncoding", + "Weight": 0.1, "Values": [ - "0", "1" ] }, { - "Name": "JitSlowDebugChecksEnabled", - "Weight": 0.002, + "Name": "HeapVerify", + "Weight": 0.1, "Values": [ - "0", "1" ] }, { - "Name": "JitSplitFunctionSize", - "Weight": 0.01, + "Name": "JitELTHookEnabled", + "Weight": 0.04, "Values": [ - "0", - "1", - "2", - "4", - "10", - "16", - "100" + "1" ] }, { - "Name": "JitStackChecks", - "Weight": 0.01, + "Name": "JitFakeProcedureSplitting", + "Weight": 0.03, "Values": [ - "0", "1" ] }, { - "Name": "InjectFault", - "Weight": 0.01, + "Name": "JitStressProcedureSplitting", + "Weight": 0.04, "Values": [ - "0", "1" ] }, { - "Name": "JitNoRngChks", - "Weight": 0.01, + "Name": "TailcallStress", + "Weight": 0.05, "Values": [ - "0", "1" ] }, { - "Name": "JitEnableNoWayAssert", - "Weight": 0.01, + "Name": "ReadyToRun", + "Weight": 0.08, "Values": [ - "0", "1" ] }, { - "Name": "JitAggressiveInlining", - "Weight": 0.05, + "Name": "JitObjectStackAllocation", + "Weight": 0.04, "Values": [ - "0", "1" ] }, { - "Name": "JitMaxLocalsToTrack", - "Weight": 0.05, + "Name": "JitClassProfiling", + "Weight": 0.04, "Values": [ - "0", - "0x10", - "0x400", - "0x800", - "0x1000" + "0" ] }, { - "Name": "JitDoAssertionProp", - "Weight": 0.05, + "Name": "JitDelegateProfiling", + "Weight": 0.04, "Values": [ - "0", - "1" + "0" ] }, { - "Name": "JitDoCopyProp", - "Weight": 0.05, + "Name": "JitVTableProfiling", + "Weight": 0.04, "Values": [ - "0", "1" ] }, { - "Name": "JitDoEarlyProp", - "Weight": 0.05, + "Name": "JitEdgeProfiling", + "Weight": 0.04, "Values": [ - "0", - "1" + "0" ] }, { - "Name": "JitDoLoopHoisting", - "Weight": 0.05, + "Name": "JitRandomGuardedDevirtualization", + "Weight": 0.04, "Values": [ - "0", "1" ] }, { - "Name": "JitDoLoopInversion", - "Weight": 0.05, + "Name": "JitRandomEdgeCounts", + "Weight": 0.04, "Values": [ - "0", "1" ] }, { - "Name": "JitDoRangeAnalysis", - "Weight": 0.05, + "Name": "JitRandomOnStackReplacement", + "Weight": 0.04, "Values": [ - "0", - "1" + "5", + "10", + "15" ] }, { - "Name": "JitDoRedundantBranchOpts", - "Weight": 0.05, + "Name": "JitGuardedDevirtualizationMaxTypeChecks", + "Weight": 0.03, "Values": [ - "0", - "1" + "1", + "2", + "3", + "5" ] }, { - "Name": "JitDoSsa", - "Weight": 0.05, + "Name": "JitRandomlyCollect64BitCounts", + "Weight": 0.03, "Values": [ - "0", "1" ] }, { - "Name": "JitDoValueNumber", - "Weight": 0.05, + "Name": "JitProfileCasts", + "Weight": 0.03, "Values": [ - "0", "1" ] }, { - "Name": "JitOptRepeat", - "Weight": 0.0005, - "Values": [ - "*" - ] - }, - { - "Name": "JitOptRepeatCount", - "Weight": 0.0003, + "Name": "TieredPGO_InstrumentedTierAlwaysOptimized", + "Weight": 0.03, "Values": [ - "2", - "3", - "4", - "5", - "6", - "10" + "1" ] }, { - "Name": "TailCallLoopOpt", - "Weight": 0.03, + "Name": "JitForceControlFlowGuard", + "Weight": 0.06, "Values": [ - "0", "1" ] }, { - "Name": "FastTailCalls", + "Name": "JitCFGUseDispatcher", "Weight": 0.03, "Values": [ "0", @@ -381,34 +275,32 @@ ] }, { - "Name": "JitEnableFinallyCloning", + "Name": "JitSynthesizeCounts", "Weight": 0.03, "Values": [ - "0", - "1" + "1", + "3", + "5" ] }, { - "Name": "JitEnableRemoveEmptyTry", + "Name": "JitCheckSynthesizedCounts", "Weight": 0.03, "Values": [ - "0", "1" ] }, { - "Name": "JitEnableGuardedDevirtualization", + "Name": "JitRLCSEGreedy", "Weight": 0.03, "Values": [ - "0", "1" ] }, { - "Name": "JitExpandCallsEarly", + "Name": "JitDoReversePostOrderLayout", "Weight": 0.03, "Values": [ - "0", "1" ] } From ab23b2f1181ba49857147dc01f635e5309ad4c5e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 20:51:12 -0700 Subject: [PATCH 131/149] Add CSE support (#8) --- Antigen/Config/ConfigOptions.cs | 5 + Antigen/Config/antigen.json | 13 +- Antigen/TestMethod.cs | 202 +++++++++++++++++--------------- Antigen/Tree/Scope.cs | 40 ++++++- 4 files changed, 159 insertions(+), 101 deletions(-) diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index f2b0c02..3ca063c 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -290,6 +290,11 @@ public class ConfigOptions /// public int MaxCaseCounts = 4; + /// + /// Probability of using CSE. + /// + public double CSEUsageProbability = 0.3; + /// /// Avx/Avx2 methods probability /// diff --git a/Antigen/Config/antigen.json b/Antigen/Config/antigen.json index c15da70..dff3bf4 100644 --- a/Antigen/Config/antigen.json +++ b/Antigen/Config/antigen.json @@ -748,7 +748,8 @@ "MaxStmtDepth": 2, "MaxExprDepth": 3, "MethodCount": 5, - "TryCatchFinallyStatementWeight": 0 + "TryCatchFinallyStatementWeight": 0, + "CSEUsageProbability": 0.45 }, { "Name": "Structs", @@ -758,7 +759,8 @@ "NestedStructProbability": 0.4, "StructFieldTypeProbability": 0.5, "StructAliasProbability": 0.5, - "StructUsageProbability": 0.8 + "StructUsageProbability": 0.8, + "CSEUsageProbability": 0.35 }, { "Name": "MethodCalls", @@ -782,7 +784,8 @@ "MethodCount": 5, "MaxStatementCount": 3, "TryCatchFinallyStatementWeight": 0.03, - "LocalVariablesLogProbability": 1.0 + "LocalVariablesLogProbability": 1.0, + "CSEUsageProbability": 0.25 }, { "Name": "ExceptionHandler", @@ -804,6 +807,7 @@ "LoopStartFromInvariantProbabilty": 0.3, "LoopStepPreBreakCondProbability": 0.6, "UseLoopInvariantVariableProbability": 1.0, + "CSEUsageProbability": 0.32, "AllowLoopCondAtEnd": false }, { @@ -815,7 +819,8 @@ "ForStatementWeight": 0.2, "DoWhileStatementWeight": 0.3, "WhileStatementWeight": 0.5, - "SwitchStatementWeight": 0.45 + "SwitchStatementWeight": 0.45, + "CSEUsageProbability": 0.48 } ] } \ No newline at end of file diff --git a/Antigen/TestMethod.cs b/Antigen/TestMethod.cs index 1fb2df7..fc41d56 100644 --- a/Antigen/TestMethod.cs +++ b/Antigen/TestMethod.cs @@ -708,139 +708,157 @@ public Expression ExprHelper(ExprKind exprKind, Tree.ValueType exprType, int dep exprKind = PRNG.Decide(0.5) ? ExprKind.LiteralExpression : ExprKind.VariableExpression; } + if (PRNG.Decide(TC.Config.CSEUsageProbability)) + { + Expression expr = CurrentScope.GetRandomExpression(exprKind, exprType); + if (expr != null) + { + return expr; + } + } + + Expression resultExpression = null; switch (exprKind) { case ExprKind.LiteralExpression: - { - return ConstantValue.GetConstantValue(exprType, TC._numerals); - } + { + resultExpression = ConstantValue.GetConstantValue(exprType, TC._numerals); + break; + } case ExprKind.VariableExpression: - { - return new VariableExpression(TC, CurrentScope.GetRandomVariable(exprType)); - } + { + resultExpression = new VariableExpression(TC, CurrentScope.GetRandomVariable(exprType)); + break; + } case ExprKind.BinaryOpExpression: - { - //Debug.Assert(depth <= TC.Config.MaxExprDepth); + { + //Debug.Assert(depth <= TC.Config.MaxExprDepth); - Operator op = GetASTUtils().GetRandomBinaryOperator(exprType); + Operator op = GetASTUtils().GetRandomBinaryOperator(exprType); - Tree.ValueType lhsExprType, rhsExprType; + Tree.ValueType lhsExprType, rhsExprType; + + if (exprType.IsVectorType) + { + // The vector type should match exactly. + lhsExprType = rhsExprType = exprType; + } + else + { + Primitive returnType = exprType.PrimitiveType; - if (exprType.IsVectorType) + if (op.HasFlag(OpFlags.Divide)) { - // The vector type should match exactly. - lhsExprType = rhsExprType = exprType; + // For '/' or '%' operations, just use int as dividend and divisor + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; } else { - Primitive returnType = exprType.PrimitiveType; + // If the return type is boolean, then take any ExprType that returns boolean. + // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. + //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, + // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and + // the literals are selected of different type ("decimal" in this example) and we get compilation error + // because they can't be casted to short. + lhsExprType = GetASTUtils().GetRandomPrimitiveType(returnType == Primitive.Boolean ? op.InputTypes : returnType); + //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); + rhsExprType = lhsExprType; - if (op.HasFlag(OpFlags.Divide)) - { - // For '/' or '%' operations, just use int as dividend and divisor - lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - rhsExprType = lhsExprType; - } - else + if (op.HasFlag(OpFlags.Shift)) { - // If the return type is boolean, then take any ExprType that returns boolean. - // However for other types, choose the same type for BinOp expression as the one used to store the result on LHS. - //TODO-future: Consider doing GetRandomExprType(op.InputTypes) below. Currently, if this is done, - // we end up getting code like (short)(1233342432.5M + 35435435.5M), where "short" is the exprType and - // the literals are selected of different type ("decimal" in this example) and we get compilation error - // because they can't be casted to short. - lhsExprType = GetASTUtils().GetRandomPrimitiveType(returnType == Primitive.Boolean ? op.InputTypes : returnType); - //Tree.ValueType lhsExprType = GetASTUtils().GetRandomExprType(op.InputTypes); - rhsExprType = lhsExprType; - - if (op.HasFlag(OpFlags.Shift)) - { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - } + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } } + } - ExprKind lhsExprKind, rhsExprKind; - if (depth < TC.Config.MaxExprDepth) - { - lhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(lhsExprType); - rhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); - } - else - { - lhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); - rhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); - } + ExprKind lhsExprKind, rhsExprKind; + if (depth < TC.Config.MaxExprDepth) + { + lhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(lhsExprType); + rhsExprKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); + } + else + { + lhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); + rhsExprKind = GetASTUtils().GetRandomTerminalExpression(_testClass, exprType); + } - // Fold arithmetic binop expressions that has constants. - // csc.exe would automatically fold that for us, but by doing it here, we eliminate generate - // errors during compiling the test case. - if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) - { - return ConstantValue.GetConstantValue(exprType, TC._numerals); - } + // Fold arithmetic binop expressions that has constants. + // csc.exe would automatically fold that for us, but by doing it here, we eliminate generate + // errors during compiling the test case. + if (op.HasFlag(OpFlags.Math) && lhsExprKind == ExprKind.LiteralExpression && rhsExprKind == ExprKind.LiteralExpression) + { + resultExpression = ConstantValue.GetConstantValue(exprType, TC._numerals); + } + else + { Expression lhs = ExprHelper(lhsExprKind, lhsExprType, depth + 1); Expression rhs = ExprHelper(rhsExprKind, rhsExprType, depth + 1); - return new CastExpression(TC, new BinaryExpression(TC, lhsExprType, lhs, op, rhs), exprType); + resultExpression = new CastExpression(TC, new BinaryExpression(TC, lhsExprType, lhs, op, rhs), exprType); } + break; + } case ExprKind.AssignExpression: - { - //Debug.Assert(depth <= TC.Config.MaxExprDepth); + { + //Debug.Assert(depth <= TC.Config.MaxExprDepth); - Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(exprType); - Tree.ValueType lhsExprType, rhsExprType; - lhsExprType = rhsExprType = exprType; + Tree.Operator assignOper = GetASTUtils().GetRandomAssignmentOperator(exprType); + Tree.ValueType lhsExprType, rhsExprType; + lhsExprType = rhsExprType = exprType; - if (!assignOper.IsVectorOper) - { - if (assignOper.HasFlag(OpFlags.Divide)) - { - // For divide, just use 'int` type. - lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - rhsExprType = lhsExprType; - } - else if (assignOper.HasFlag(OpFlags.Shift)) - { - rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); - } - } - - ExprKind rhsKind; - if (depth < TC.Config.MaxExprDepth) + if (!assignOper.IsVectorOper) + { + if (assignOper.HasFlag(OpFlags.Divide)) { - rhsKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); + // For divide, just use 'int` type. + lhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); + rhsExprType = lhsExprType; } - else + else if (assignOper.HasFlag(OpFlags.Shift)) { - rhsKind = GetASTUtils().GetRandomTerminalExpression(_testClass, rhsExprType); + rhsExprType = Tree.ValueType.ForPrimitive(Primitive.Int); } + } - Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); - Expression rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); - - return new CastExpression(TC, new AssignExpression(TC, lhsExprType, lhs, assignOper, rhs), exprType); + ExprKind rhsKind; + if (depth < TC.Config.MaxExprDepth) + { + rhsKind = GetASTUtils().GetRandomExpressionReturningValueType(rhsExprType); } - case ExprKind.MethodCallExpression: + else { - if (depth < TC.Config.MaxExprDepth) - { - return MethodCallHelper(_testClass.GetRandomMethod(exprType), depth + 1); - } - else - { - return MethodCallHelper(_testClass.GetRandomLeafMethod(exprType), depth + 1); - } + rhsKind = GetASTUtils().GetRandomTerminalExpression(_testClass, rhsExprType); } + Expression lhs = ExprHelper(ExprKind.VariableExpression, lhsExprType, depth + 1); + Expression rhs = ExprHelper(rhsKind, rhsExprType, depth + 1); + + resultExpression = new CastExpression(TC, new AssignExpression(TC, lhsExprType, lhs, assignOper, rhs), exprType); + break; + } + case ExprKind.MethodCallExpression: + { + resultExpression = depth < TC.Config.MaxExprDepth + ? MethodCallHelper(_testClass.GetRandomMethod(exprType), depth + 1) + : MethodCallHelper(_testClass.GetRandomLeafMethod(exprType), depth + 1); + break; + } + default: Debug.Assert(false, string.Format("Hit unknown expression type {0}", Enum.GetName(typeof(ExprKind), exprKind))); break; } - return null; + + if (resultExpression != null) + { + CurrentScope.AddExpression(exprKind, exprType, resultExpression); + } + return resultExpression; } /// diff --git a/Antigen/Tree/Scope.cs b/Antigen/Tree/Scope.cs index 68b5b98..b845790 100644 --- a/Antigen/Tree/Scope.cs +++ b/Antigen/Tree/Scope.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Antigen.Expressions; using Antigen.Statements; namespace Antigen.Tree @@ -49,6 +50,8 @@ public class Scope // List of string vars in the current scope. private List LocalStringVariables = new List(); + public Dictionary> ListOfExpressions = new Dictionary>(); + #region Contructors public Scope(TestCase tc) { @@ -92,16 +95,43 @@ public ValueType GetRandomStructType() return ListOfStructTypes[PRNG.Next(ListOfStructTypes.Count)]; } - #endregion - - #region Gets From Scope - public int GetVariablesCount() + public Expression GetRandomExpression(ExprKind exprKind, ValueType exprType) { - return ListOfVariables.Count; + var key = $"{Enum.GetName(typeof(ExprKind), exprKind)}_{exprType}"; + Expression expression = null; + var curr = this; + + while (curr != null) + { + if (curr.ListOfExpressions.TryGetValue(key, out List expressions)) + { + expression = expressions[PRNG.Next(expressions.Count)]; + if (PRNG.Decide(0.3)) + { + return expression; + } + } + curr = curr.parent; + } + return expression; } + #endregion #region Add variables/types to scope + + public void AddExpression(ExprKind exprKind, ValueType exprType, Expression expr) + { + var key = $"{Enum.GetName(typeof(ExprKind), exprKind)}_{exprType}"; + + if (!ListOfExpressions.ContainsKey(key)) + { + ListOfExpressions[key] = new List(); + } + + ListOfExpressions[key].Add(expr); + } + public void AddLocal(ValueType variableType, string variableName) { //#if DEBUG From 0fcd3bf7eccecccd627ddd8f54c53027addf0656 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 21:10:29 -0700 Subject: [PATCH 132/149] Save OutputMismatch in same folder --- Antigen/TestCase.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 29c8036..850a0c6 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -45,8 +45,8 @@ public enum CompilationType private class UniqueIssueFile { public readonly int UniqueIssueId; - public readonly int FileSize; - public readonly string FileName; + public int FileSize { get; private set; } + public string FileName { get; private set; } public int HitCount { get; private set; } public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName, int hitCount) @@ -61,6 +61,12 @@ public void IncreaseHitCount() { HitCount++; } + + public void UpdateIssueFileDetails(string fileName, int fileSize) + { + FileName = fileName; + FileSize = fileSize; + } } private static readonly ConcurrentDictionary s_uniqueIssues = new(); @@ -203,7 +209,7 @@ public TestResult Verify() case RunOutcome.OutputMismatch: { var outputDiff = executeResult.OtherErrorMessage; - SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, outputDiff, executeResult.EnvVars, outputDiff, $"{Name}-test-output-mismatch"); + SaveTestCase(compileResult.AssemblyFullPath, testCaseRoot, outputDiff, executeResult.EnvVars, "OutputMismatch", $"{ Name}-test-output-mismatch"); return TestResult.OutputMismatch; } case RunOutcome.Timeout: @@ -265,6 +271,7 @@ private void SaveTestCase( if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile, 0); + s_uniqueIssues[assertionHashCode] = uniqueIssueFile; } else { @@ -290,7 +297,7 @@ private void SaveTestCase( if (uniqueIssueFile.FileSize > fileContents.Length) { string largerReproFile = Path.Combine(uniqueIssueDirName, uniqueIssueFile.FileName); - if (File.Exists(largerReproFile)) + if ((failureText != "OutputMismatch") && File.Exists(largerReproFile)) { File.Delete(largerReproFile); } @@ -300,7 +307,7 @@ private void SaveTestCase( File.WriteAllText(failFile, fileContents.ToString()); // Update the file size - s_uniqueIssues[assertionHashCode] = new UniqueIssueFile(uniqueIssueFile.UniqueIssueId, fileContents.Length, currentReproFile, uniqueIssueFile.HitCount); + uniqueIssueFile.UpdateIssueFileDetails(currentReproFile, fileContents.Length); } } } From 6bba212fa018ccb09ec4c9a4118cff6e57be85f9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 21:14:22 -0700 Subject: [PATCH 133/149] Make sure proxy is running --- Antigen/Execution/EEDriver.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Antigen/Execution/EEDriver.cs b/Antigen/Execution/EEDriver.cs index 70d8436..bfed47c 100644 --- a/Antigen/Execution/EEDriver.cs +++ b/Antigen/Execution/EEDriver.cs @@ -58,7 +58,10 @@ private EEProxy Get() var proxy = Proxys[leastUsedIndex]; Proxys[leastUsedIndex] = Proxys[Proxys.Count - 1]; Proxys.RemoveAt(Proxys.Count - 1); - return proxy; + if (proxy.IsRunning) + { + return proxy; + } } } From d2e0c53f197447bc917e9759f2bf465d03e49b36 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 14 Aug 2024 23:12:41 -0700 Subject: [PATCH 134/149] catch exception, but return 0 --- Antigen/Antigen.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 6f588b6..d60d801 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -93,6 +93,11 @@ private static int Run(CommandLineOptions opts) Console.WriteLine($" Paged memory size : {myProcess.PagedMemorySize64}"); return 1; } + catch (Exception ex) + { + Console.WriteLine("Got following exception, but will return exitcode= 0 so issues folder gets copied."); + Console.WriteLine(ex.Message); + } return 0; } From 7f81f23729afd0680050f8c82188a8fde9abeff0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 01:16:29 -0700 Subject: [PATCH 135/149] Out of proc Trimmer (#9) * In-built Trimmer * Create Utilities project * minor fixes --- Antigen.sln | 6 + Antigen/Antigen.cs | 49 ++++++-- Antigen/Antigen.csproj | 7 +- ExecutionEngine/ExecutionEngine.csproj | 4 + Trimmer/TestTrimmer.cs | 115 +++++++++++++----- Trimmer/Trimmer.csproj | 14 +-- .../Compilation/CompileResult.cs | 2 +- .../Compilation/Compiler.cs | 8 +- {Antigen => Utilities}/Execution/EEDriver.cs | 2 +- {Antigen => Utilities}/Execution/EEProxy.cs | 4 +- .../Execution/ExecuteResult.cs | 24 ++-- .../RequestResponse.cs | 0 {Utils => Utilities}/RslnUtilities.cs | 2 +- {Utils => Utilities}/TestRunner.cs | 4 +- Utilities/Utilities.csproj | 16 +++ 15 files changed, 173 insertions(+), 84 deletions(-) rename {Antigen => Utilities}/Compilation/CompileResult.cs (97%) rename {Antigen => Utilities}/Compilation/Compiler.cs (95%) rename {Antigen => Utilities}/Execution/EEDriver.cs (99%) rename {Antigen => Utilities}/Execution/EEProxy.cs (97%) rename {Antigen => Utilities}/Execution/ExecuteResult.cs (63%) rename {ExecutionEngine => Utilities}/RequestResponse.cs (100%) rename {Utils => Utilities}/RslnUtilities.cs (98%) rename {Utils => Utilities}/TestRunner.cs (96%) create mode 100644 Utilities/Utilities.csproj diff --git a/Antigen.sln b/Antigen.sln index dc69bf1..4fe5c9f 100644 --- a/Antigen.sln +++ b/Antigen.sln @@ -14,6 +14,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trimmer", "Trimmer\Trimmer. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionEngine", "ExecutionEngine\ExecutionEngine.csproj", "{1A2BB825-9952-479B-8F6A-7F0543B0A4FC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utilities", "Utilities\Utilities.csproj", "{83B6CBCC-4955-436B-9380-EE50CDC69429}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,6 +34,10 @@ Global {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A2BB825-9952-479B-8F6A-7F0543B0A4FC}.Release|Any CPU.Build.0 = Release|Any CPU + {83B6CBCC-4955-436B-9380-EE50CDC69429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83B6CBCC-4955-436B-9380-EE50CDC69429}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83B6CBCC-4955-436B-9380-EE50CDC69429}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83B6CBCC-4955-436B-9380-EE50CDC69429}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index d60d801..9a30e8c 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -75,6 +75,15 @@ private static int Run(CommandLineOptions opts) Directory.CreateDirectory(s_runOptions.OutputDirectory); } + StartTrimmer(opts); + + TestCase.s_RunOptions = s_runOptions; + TestCase.s_Driver = EEDriver.GetInstance(s_runOptions.CoreRun, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), () => EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), false)); + TestCase.s_TestRunner = TestRunner.GetInstance(TestCase.s_Driver, s_runOptions.CoreRun, s_runOptions.OutputDirectory); + + // Generate vector methods + VectorHelpers.RecordVectorMethods(); + Parallel.For(0, 4, (p) => RunTest()); Console.WriteLine($"Executed {s_testId} test cases."); DisplayStats(); @@ -101,6 +110,33 @@ private static int Run(CommandLineOptions opts) return 0; } + private static void StartTrimmer(CommandLineOptions opts) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trimmer.exe"), + Arguments = $"-c {opts.CoreRunPath} -o {opts.IssuesFolder} -p {Environment.ProcessId}", // Optional: arguments for the process + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + Process process = new Process + { + StartInfo = startInfo + }; + process.Start(); + if (process.HasExited) + { + Console.WriteLine("Trimmer exited immediately."); + } + else + { + Console.WriteLine($"Started Trimmer with PID {process.Id}"); + } + } + private static int GetNextTestId() { lock (s_spinLock) @@ -176,19 +212,6 @@ static void RunTest() { TestResult.Timeout, 0 }, }; - lock (s_spinLock) - { - if (TestCase.s_RunOptions == null) - { - TestCase.s_RunOptions = s_runOptions; - TestCase.s_Driver = EEDriver.GetInstance(s_runOptions.CoreRun, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), () => EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), false)); - TestCase.s_TestRunner = TestRunner.GetInstance(TestCase.s_Driver, s_runOptions.CoreRun, s_runOptions.OutputDirectory); - - // Generate vector methods - VectorHelpers.RecordVectorMethods(); - } - } - int testCount = 0; while (!Done) { diff --git a/Antigen/Antigen.csproj b/Antigen/Antigen.csproj index 7e56303..a2aee0a 100644 --- a/Antigen/Antigen.csproj +++ b/Antigen/Antigen.csproj @@ -18,11 +18,6 @@ - - - - - false @@ -33,6 +28,8 @@ + + diff --git a/ExecutionEngine/ExecutionEngine.csproj b/ExecutionEngine/ExecutionEngine.csproj index 88a4f80..6a3b486 100644 --- a/ExecutionEngine/ExecutionEngine.csproj +++ b/ExecutionEngine/ExecutionEngine.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index ef810a0..805ebab 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -12,12 +12,14 @@ using Microsoft.CodeAnalysis.CSharp; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Utils; @@ -32,16 +34,22 @@ public struct ReproDetails public class TestTrimmer { + const int TRIMMER_RESET_COUNT = 10; + const int TRIMMER_TIMEOUT_IN_MINS = 10; + const int TRIMMER_NEW_FOLDER_CHECK_IN_MINS = 10; + const int SAVE_LKG_EVERY = 100; + private SyntaxNode _treeToTrim; private ExecuteResult _lkgExecuteResult; private int _sizeOfTestFileToTrim; private static TestRunner _testRunner; + private static int s_parentProcessId; private int _iterId = 0; - static int TRIMMER_RESET_COUNT = 10; private readonly CommandLineOptions _opts = null; private readonly Compiler _compiler; private readonly ReproDetails _reproDetails; - private readonly string _issueFolder; + private readonly string _issueTopFolder; + private string _issueFolder; static int Main(string[] args) { @@ -50,20 +58,47 @@ static int Main(string[] args) private static int Run(CommandLineOptions opts) { - string testCaseToTrim = opts.ReproFile; - TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, opts); - testTrimmer.Trim(); - testTrimmer.SaveRepro(); - return 0; + int.TryParse(opts.ParentPid, out s_parentProcessId); + Task monitorTask = Task.Run(() => MonitorParentProcess()); + + int uniqueId = 0; + while (true) + { + string uniqueFolder = Path.Combine(opts.IssuesFolder, $"UniqueIssue{uniqueId}"); + if (!Directory.Exists(uniqueFolder)) + { + Thread.Sleep(TRIMMER_NEW_FOLDER_CHECK_IN_MINS * 60 * 1000); // wait for 10 minutes + continue; + } + + string[] csFiles = Directory.GetFiles(uniqueFolder, "*.cs", SearchOption.AllDirectories); + if (csFiles.Length == 0) + { + Thread.Sleep(TRIMMER_NEW_FOLDER_CHECK_IN_MINS * 60 * 1000); // wait for 10 minutes + continue; + } + uniqueId++; + + // Create FileInfo objects and sort by file size + var testCaseToTrim = csFiles + .Select(file => new FileInfo(file)) + .OrderBy(fileInfo => fileInfo.Length) // Sort by file size + .First().FullName; + + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, opts); + testTrimmer._issueFolder = uniqueFolder; + testTrimmer.Trim(); + testTrimmer.SaveRepro(); + } } public TestTrimmer(string testFileToTrim, CommandLineOptions opts) { - if (!File.Exists(testFileToTrim)) + if (!System.IO.File.Exists(testFileToTrim)) { throw new Exception($"{testFileToTrim} doesn't exist."); } - _issueFolder = opts.IssuesFolder; + _issueTopFolder = opts.IssuesFolder; _opts = opts; _compiler = new Compiler(opts.IssuesFolder); @@ -98,16 +133,6 @@ private ReproDetails ParseReproFile(string testFileToTrim) { var testContents = lineContent.Replace("// EnvVars: ", string.Empty).Trim(); var testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); - - if (!string.IsNullOrEmpty(_opts.AltJitName)) - { - testVariables["DOTNET_AltJitName"] = _opts.AltJitName; - } - - if (!string.IsNullOrEmpty(_opts.AltJitMethodName)) - { - testVariables["DOTNET_AltJit"] = _opts.AltJitMethodName; - } reproDetails.envVars = testVariables; break; } @@ -144,8 +169,12 @@ private ReproDetails ParseReproFile(string testFileToTrim) public void Trim() { - var trimTask = Task.Run(TrimTree); - trimTask.Wait(TimeSpan.FromMinutes(40)); + try + { + var trimTask = Task.Run(TrimTree); + trimTask.Wait(TimeSpan.FromMinutes(TRIMMER_TIMEOUT_IN_MINS)); + } + catch { } } /// @@ -438,7 +467,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode/*, bool skip throw new Exception("Unknown outcome."); } - if (_iterId % 100 == 0) + if (_iterId % SAVE_LKG_EVERY == 0) { SaveRepro(); } @@ -454,6 +483,10 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode/*, bool skip private void SaveRepro() { + if (_treeToTrim == null) + { + return; + } string programContents = _treeToTrim.ToFullString(); programContents = Regex.Replace(programContents, @"[\r\n]*$", string.Empty, RegexOptions.Multiline); @@ -509,6 +542,34 @@ private static string GetReadableFileSize(double len) // show a single decimal place, and no space. return String.Format("{0:0.##} {1}", len, sizes[order]); } + + + /// + /// Monitor parent process every 10 seconds and exit if it terminates + /// + private static void MonitorParentProcess() + { + if (s_parentProcessId == 0) + { + // No need to monitor parent process + return; + } + try + { + while (true) + { + // Check if the parent process is still running + Process.GetProcessById(s_parentProcessId); + Thread.Sleep(10000); // Check every 10 seconds + } + } + catch (ArgumentException) + { + // Parent process is no longer running + Console.WriteLine("Parent process terminated. Exiting..."); + Environment.Exit(0); + } + } } public class CommandLineOptions @@ -516,16 +577,10 @@ public class CommandLineOptions [Option(shortName: 'c', longName: "CoreRun", Required = true, HelpText = "Path to CoreRun/CoreRun.exe.")] public string CoreRunPath { get; set; } - [Option(shortName: 'f', longName: "ReproFile", Required = true, HelpText = "Full path of the repro file.")] - public string ReproFile { get; set; } + [Option(shortName: 'p', longName: "ParentPid", Required = false, HelpText = "Antigen process id")] + public string ParentPid { get; set; } [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where trimmed issue will be copied.")] public string IssuesFolder { get; set; } - - [Option(shortName: 'j', longName: "AltJitName", Required = false, HelpText = "Name of altjit. By default, current OS/arch.")] - public string AltJitName { get; set; } - - [Option(shortName: 'm', longName: "AltJitMethodName", Required = false, HelpText = "Name of method for altjit. By default, current OS/arch.")] - public string AltJitMethodName { get; set; } } } diff --git a/Trimmer/Trimmer.csproj b/Trimmer/Trimmer.csproj index 52ffa91..4c6a9ed 100644 --- a/Trimmer/Trimmer.csproj +++ b/Trimmer/Trimmer.csproj @@ -11,21 +11,9 @@ - - - - - - - - - - - - - + diff --git a/Antigen/Compilation/CompileResult.cs b/Utilities/Compilation/CompileResult.cs similarity index 97% rename from Antigen/Compilation/CompileResult.cs rename to Utilities/Compilation/CompileResult.cs index bdf3c31..e6a592d 100644 --- a/Antigen/Compilation/CompileResult.cs +++ b/Utilities/Compilation/CompileResult.cs @@ -11,7 +11,7 @@ namespace Antigen.Compilation { - internal struct CompileResult + public struct CompileResult { public CompileResult(IEnumerable diagnostics) { diff --git a/Antigen/Compilation/Compiler.cs b/Utilities/Compilation/Compiler.cs similarity index 95% rename from Antigen/Compilation/Compiler.cs rename to Utilities/Compilation/Compiler.cs index de3c0ca..2ef8f19 100644 --- a/Antigen/Compilation/Compiler.cs +++ b/Utilities/Compilation/Compiler.cs @@ -15,7 +15,7 @@ namespace Antigen.Compilation { - internal class Compiler + public class Compiler { private static readonly CSharpCompilationOptions ReleaseCompileOptions = new( OutputKind.ConsoleApplication, @@ -39,12 +39,12 @@ internal class Compiler private readonly string m_outputDirectory; - internal Compiler(string outputDirectory) + public Compiler(string outputDirectory) { m_outputDirectory = outputDirectory; } - internal CompileResult Compile(SyntaxTree programTree, string assemblyName) + public CompileResult Compile(SyntaxTree programTree, string assemblyName) { var debugBytes = CompileAndGetBytes(programTree, assemblyName, DebugCompileOptions); var releaseBytes = CompileAndGetBytes(programTree, assemblyName, ReleaseCompileOptions); @@ -71,7 +71,7 @@ private byte[] CompileAndGetBytes(SyntaxTree programTree, string assemblyName, C if (!result.Success) { -#if DEBUG +#if UNREACHABLE SaveCompilationError(programTree, result.Diagnostics); #endif return null; diff --git a/Antigen/Execution/EEDriver.cs b/Utilities/Execution/EEDriver.cs similarity index 99% rename from Antigen/Execution/EEDriver.cs rename to Utilities/Execution/EEDriver.cs index bfed47c..155d498 100644 --- a/Antigen/Execution/EEDriver.cs +++ b/Utilities/Execution/EEDriver.cs @@ -10,7 +10,7 @@ namespace Antigen.Execution { // Driver that creates EEProxy instances and responsible for its lifetime. - internal class EEDriver + public class EEDriver { private readonly string _hostName; private readonly string _executionEngine; diff --git a/Antigen/Execution/EEProxy.cs b/Utilities/Execution/EEProxy.cs similarity index 97% rename from Antigen/Execution/EEProxy.cs rename to Utilities/Execution/EEProxy.cs index 2cc918c..c9f9fce 100644 --- a/Antigen/Execution/EEProxy.cs +++ b/Utilities/Execution/EEProxy.cs @@ -20,7 +20,7 @@ namespace Antigen.Execution { // Each instance of class represents a corresponding instance of ExecutionEngine - internal class EEProxy + public class EEProxy { public readonly Process _process; public Stopwatch LastUsedTime { get; } = new Stopwatch(); @@ -84,7 +84,7 @@ public override string ToString() return result; } - internal static EEProxy GetInstance(string host, string executionEngine, Dictionary envVars) + public static EEProxy GetInstance(string host, string executionEngine, Dictionary envVars) { if (!File.Exists(host) || !File.Exists(executionEngine)) { diff --git a/Antigen/Execution/ExecuteResult.cs b/Utilities/Execution/ExecuteResult.cs similarity index 63% rename from Antigen/Execution/ExecuteResult.cs rename to Utilities/Execution/ExecuteResult.cs index 849004b..7655a78 100644 --- a/Antigen/Execution/ExecuteResult.cs +++ b/Utilities/Execution/ExecuteResult.cs @@ -21,42 +21,42 @@ public enum RunOutcome CompilationError, } - internal struct ExecuteResult + public struct ExecuteResult { - internal string OtherErrorMessage { get; private set; } - internal string AssertionMessage { get; private set; } - internal string ShortAssertionText { get; private set; } - internal RunOutcome Result { get; private set; } - internal IReadOnlyList> EnvVars { get; private set; } + public string OtherErrorMessage { get; private set; } + public string AssertionMessage { get; private set; } + public string ShortAssertionText { get; private set; } + public RunOutcome Result { get; private set; } + public IReadOnlyList> EnvVars { get; private set; } - internal static ExecuteResult GetSuccessResult() + public static ExecuteResult GetSuccessResult() { return new ExecuteResult(RunOutcome.Success, null); } - internal static ExecuteResult GetOtherErrorResult(string errorMessage, IReadOnlyList> envVars) + public static ExecuteResult GetOtherErrorResult(string errorMessage, IReadOnlyList> envVars) { return new ExecuteResult(RunOutcome.OtherError, null, errorMessage, envVars); } - internal static ExecuteResult GetTimeoutResult() + public static ExecuteResult GetTimeoutResult() { return new ExecuteResult(RunOutcome.Timeout, null); } - internal static ExecuteResult GetAssertionFailureResult(string assertionMessage, IReadOnlyList> envVars) + public static ExecuteResult GetAssertionFailureResult(string assertionMessage, IReadOnlyList> envVars) { var result = new ExecuteResult(RunOutcome.AssertionFailure, assertionMessage, null, envVars); result.ShortAssertionText = RslnUtilities.ParseAssertionError(assertionMessage); return result; } - internal static ExecuteResult GetOutputMismatchResult(string outputDiff, IReadOnlyList> envVars) + public static ExecuteResult GetOutputMismatchResult(string outputDiff, IReadOnlyList> envVars) { return new ExecuteResult(RunOutcome.OutputMismatch, null, outputDiff, envVars); } - internal static ExecuteResult GetCompilationError() + public static ExecuteResult GetCompilationError() { return new ExecuteResult(RunOutcome.CompilationError, null); } diff --git a/ExecutionEngine/RequestResponse.cs b/Utilities/RequestResponse.cs similarity index 100% rename from ExecutionEngine/RequestResponse.cs rename to Utilities/RequestResponse.cs diff --git a/Utils/RslnUtilities.cs b/Utilities/RslnUtilities.cs similarity index 98% rename from Utils/RslnUtilities.cs rename to Utilities/RslnUtilities.cs index 859ff3f..bc4be7a 100644 --- a/Utils/RslnUtilities.cs +++ b/Utilities/RslnUtilities.cs @@ -73,7 +73,7 @@ private static void FindTreeDiff(SyntaxNode expected, SyntaxNode actual) /// /// /// - internal static string ParseAssertionError(string output) + public static string ParseAssertionError(string output) { if (string.IsNullOrEmpty(output)) { diff --git a/Utils/TestRunner.cs b/Utilities/TestRunner.cs similarity index 96% rename from Utils/TestRunner.cs rename to Utilities/TestRunner.cs index af50ded..456c94f 100644 --- a/Utils/TestRunner.cs +++ b/Utilities/TestRunner.cs @@ -66,7 +66,7 @@ private TestRunner(EEDriver driver, string coreRun, string outputFolder) _driver = driver; } - internal static TestRunner GetInstance(EEDriver driver, string coreRun, string outputFolder) + public static TestRunner GetInstance(EEDriver driver, string coreRun, string outputFolder) { if (_testRunner == null) { @@ -75,7 +75,7 @@ internal static TestRunner GetInstance(EEDriver driver, string coreRun, string o return _testRunner; } - internal ExecuteResult Execute(CompileResult compileResult) + public ExecuteResult Execute(CompileResult compileResult) { if (compileResult.DebugAssembly == null || compileResult.ReleaseAssembly == null) { diff --git a/Utilities/Utilities.csproj b/Utilities/Utilities.csproj new file mode 100644 index 0000000..7452827 --- /dev/null +++ b/Utilities/Utilities.csproj @@ -0,0 +1,16 @@ + + + + net9.0 + enable + enable + + + + + + + + + + From 591a146ec44ea89d3388049e36931d3f6598a10b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 03:21:44 -0700 Subject: [PATCH 136/149] fix the trimmer.exe path for non-windows --- Antigen/Antigen.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 9a30e8c..832b3f9 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -10,6 +10,7 @@ using System.Runtime.CompilerServices; using Antigen.Execution; using System.Reflection; +using System.Runtime.InteropServices; namespace Antigen { @@ -112,9 +113,14 @@ private static int Run(CommandLineOptions opts) private static void StartTrimmer(CommandLineOptions opts) { + string trimmer_exe = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trimmer"); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + trimmer_exe += ".exe"; + } ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trimmer.exe"), + FileName = trimmer_exe, Arguments = $"-c {opts.CoreRunPath} -o {opts.IssuesFolder} -p {Environment.ProcessId}", // Optional: arguments for the process UseShellExecute = false, RedirectStandardInput = true, From 0f25c5e0d5c4a1e468b7387126878045db90b057 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 07:19:09 -0700 Subject: [PATCH 137/149] fix trimmer bug --- Trimmer/TestTrimmer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 805ebab..b2b5230 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -129,14 +129,17 @@ private ReproDetails ParseReproFile(string testFileToTrim) { var lineContent = line.Trim(); - if (lineContent.StartsWith("// EnvVars: ")) + if (lineContent.StartsWith("// EnvVars:")) { var testContents = lineContent.Replace("// EnvVars: ", string.Empty).Trim(); var testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); reproDetails.envVars = testVariables; break; } + } + if (reproDetails.envVars == null) + { throw new Exception("EnvVars not present."); } @@ -454,7 +457,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode/*, bool skip break; case RunOutcome.AssertionFailure: validationResult = _reproDetails.assertionText == executeResult.ShortAssertionText ? - TestResult.Pass : TestResult.Assertion; + TestResult.Assertion : TestResult.Pass; break; case RunOutcome.OutputMismatch: validationResult = TestResult.OutputMismatch; From 6c22f71cf7444a239f5f7a0bbfbaf3ef27741ee8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 09:50:57 -0700 Subject: [PATCH 138/149] Add option for RunOne --- Trimmer/TestTrimmer.cs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index b2b5230..4affc7e 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -48,7 +48,6 @@ public class TestTrimmer private readonly CommandLineOptions _opts = null; private readonly Compiler _compiler; private readonly ReproDetails _reproDetails; - private readonly string _issueTopFolder; private string _issueFolder; static int Main(string[] args) @@ -57,6 +56,18 @@ static int Main(string[] args) } private static int Run(CommandLineOptions opts) + { + if (!string.IsNullOrEmpty(opts.ReproFile) && File.Exists(opts.ReproFile)) + { + return RunOne(opts); + } + else + { + return RunMany(opts); + } + } + + private static int RunMany(CommandLineOptions opts) { int.TryParse(opts.ParentPid, out s_parentProcessId); Task monitorTask = Task.Run(() => MonitorParentProcess()); @@ -92,13 +103,21 @@ private static int Run(CommandLineOptions opts) } } + private static int RunOne(CommandLineOptions opts) + { + TestTrimmer testTrimmer = new TestTrimmer(opts.ReproFile, opts); + testTrimmer._issueFolder = opts.IssuesFolder; + testTrimmer.Trim(); + testTrimmer.SaveRepro(); + return 0; + } + public TestTrimmer(string testFileToTrim, CommandLineOptions opts) { if (!System.IO.File.Exists(testFileToTrim)) { throw new Exception($"{testFileToTrim} doesn't exist."); } - _issueTopFolder = opts.IssuesFolder; _opts = opts; _compiler = new Compiler(opts.IssuesFolder); @@ -133,6 +152,16 @@ private ReproDetails ParseReproFile(string testFileToTrim) { var testContents = lineContent.Replace("// EnvVars: ", string.Empty).Trim(); var testVariables = testContents.Split("|").ToList().ToDictionary(x => x.Split("=")[0], x => x.Split("=")[1]); + + if (!string.IsNullOrEmpty(_opts.AltJitName)) + { + testVariables["DOTNET_AltJitName"] = _opts.AltJitName; + } + + if (!string.IsNullOrEmpty(_opts.AltJitMethodName)) + { + testVariables["DOTNET_AltJit"] = _opts.AltJitMethodName; + } reproDetails.envVars = testVariables; break; } @@ -585,5 +614,14 @@ public class CommandLineOptions [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where trimmed issue will be copied.")] public string IssuesFolder { get; set; } + + [Option(shortName: 'f', longName: "ReproFile", Required = false, HelpText = "Full path of the repro file.")] + public string ReproFile { get; set; } + + [Option(shortName: 'j', longName: "AltJitName", Required = false, HelpText = "Name of altjit. By default, current OS/arch.")] + public string AltJitName { get; set; } + + [Option(shortName: 'm', longName: "AltJitMethodName", Required = false, HelpText = "Name of method for altjit. By default, current OS/arch.")] + public string AltJitMethodName { get; set; } } } From 4df63ef154ffacbb49302316df859cb2095f28a5 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 09:53:49 -0700 Subject: [PATCH 139/149] update some timeouts --- Trimmer/TestTrimmer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 4affc7e..0ad7c2a 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -35,8 +35,8 @@ public struct ReproDetails public class TestTrimmer { const int TRIMMER_RESET_COUNT = 10; - const int TRIMMER_TIMEOUT_IN_MINS = 10; - const int TRIMMER_NEW_FOLDER_CHECK_IN_MINS = 10; + const int TRIMMER_TIMEOUT_IN_MINS = 15; + const int TRIMMER_NEW_FOLDER_CHECK_IN_MINS = 5; const int SAVE_LKG_EVERY = 100; private SyntaxNode _treeToTrim; From 3eb01c21523856f8e32b82c5e5a32b9a17c676e6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 20:22:43 -0700 Subject: [PATCH 140/149] Make Trimmer run for every issue when found --- Antigen/Antigen.cs | 50 +++++++++++++++++++++++++++++++++++++---- Antigen/TestCase.cs | 35 +++++++---------------------- Trimmer/TestTrimmer.cs | 27 +++++++++++----------- Utilities/TestRunner.cs | 8 +++---- 4 files changed, 71 insertions(+), 49 deletions(-) diff --git a/Antigen/Antigen.cs b/Antigen/Antigen.cs index 832b3f9..e87a8d5 100644 --- a/Antigen/Antigen.cs +++ b/Antigen/Antigen.cs @@ -76,11 +76,13 @@ private static int Run(CommandLineOptions opts) Directory.CreateDirectory(s_runOptions.OutputDirectory); } - StartTrimmer(opts); + // Disable trimmer for folder and instead start trimmer for a specific repro file + // when it comes. + //StartTrimmerForFolder(opts); TestCase.s_RunOptions = s_runOptions; TestCase.s_Driver = EEDriver.GetInstance(s_runOptions.CoreRun, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), () => EnvVarOptions.TestVars(includeOsrSwitches: PRNG.Decide(0.3), false)); - TestCase.s_TestRunner = TestRunner.GetInstance(TestCase.s_Driver, s_runOptions.CoreRun, s_runOptions.OutputDirectory); + TestCase.s_TestRunner = TestRunner.GetInstance(TestCase.s_Driver, s_runOptions.CoreRun); // Generate vector methods VectorHelpers.RecordVectorMethods(); @@ -111,7 +113,47 @@ private static int Run(CommandLineOptions opts) return 0; } - private static void StartTrimmer(CommandLineOptions opts) + /// + /// Start trimmer for entire folder. Trimmer will monitor if there is any new UniqueIssue* folder + /// and if yes, trim the repro file. + /// + private static void StartTrimmerForFolder() + { + string trimmer_exe = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trimmer"); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + trimmer_exe += ".exe"; + } + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = trimmer_exe, + Arguments = $"-c {s_runOptions.CoreRun} -o {s_runOptions.OutputDirectory} -p {Environment.ProcessId}", + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + Process process = new Process + { + StartInfo = startInfo + }; + process.Start(); + if (process.HasExited) + { + Console.WriteLine("Trimmer exited immediately."); + } + else + { + Console.WriteLine($"Started Trimmer with PID {process.Id}"); + } + } + + /// + /// Start trimmer for a specific repro file. + /// + /// + internal static void StartTrimmerForFile(string reproFile) { string trimmer_exe = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trimmer"); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -121,7 +163,7 @@ private static void StartTrimmer(CommandLineOptions opts) ProcessStartInfo startInfo = new ProcessStartInfo { FileName = trimmer_exe, - Arguments = $"-c {opts.CoreRunPath} -o {opts.IssuesFolder} -p {Environment.ProcessId}", // Optional: arguments for the process + Arguments = $"-c {s_runOptions.CoreRun} -f {reproFile} -p {Environment.ProcessId}", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 850a0c6..59a00d5 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -45,15 +45,11 @@ public enum CompilationType private class UniqueIssueFile { public readonly int UniqueIssueId; - public int FileSize { get; private set; } - public string FileName { get; private set; } public int HitCount { get; private set; } - public UniqueIssueFile(int _uniqueIssueId, int _fileSize, string _fileName, int hitCount) + public UniqueIssueFile(int _uniqueIssueId, int hitCount) { UniqueIssueId = _uniqueIssueId; - FileSize = _fileSize; - FileName = _fileName; HitCount = hitCount; } @@ -61,12 +57,6 @@ public void IncreaseHitCount() { HitCount++; } - - public void UpdateIssueFileDetails(string fileName, int fileSize) - { - FileName = fileName; - FileSize = fileSize; - } } private static readonly ConcurrentDictionary s_uniqueIssues = new(); @@ -270,7 +260,7 @@ private void SaveTestCase( UniqueIssueFile uniqueIssueFile; if (!s_uniqueIssues.ContainsKey(assertionHashCode)) { - uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, int.MaxValue, currentReproFile, 0); + uniqueIssueFile = new UniqueIssueFile(s_uniqueIssues.Count, 0); s_uniqueIssues[assertionHashCode] = uniqueIssueFile; } else @@ -282,7 +272,6 @@ private void SaveTestCase( summaryContents.AppendLine(); summaryContents.AppendLine($"HitCount: {uniqueIssueFile.HitCount}"); - // Create hash of testAssertion and copy files in respective bucket. uniqueIssueDirName = Path.Combine(s_RunOptions.OutputDirectory, $"UniqueIssue{uniqueIssueFile.UniqueIssueId}"); @@ -293,22 +282,14 @@ private void SaveTestCase( File.WriteAllText(Path.Combine(uniqueIssueDirName, "summary.txt"), summaryContents.ToString()); - // Only cache 1 file of smallest possible size. - if (uniqueIssueFile.FileSize > fileContents.Length) + if (uniqueIssueFile.HitCount > 1) { - string largerReproFile = Path.Combine(uniqueIssueDirName, uniqueIssueFile.FileName); - if ((failureText != "OutputMismatch") && File.Exists(largerReproFile)) - { - File.Delete(largerReproFile); - } - - // Write the smallest file - string failFile = Path.Combine(uniqueIssueDirName, currentReproFile); - File.WriteAllText(failFile, fileContents.ToString()); - - // Update the file size - uniqueIssueFile.UpdateIssueFileDetails(currentReproFile, fileContents.Length); + return; } + + string failFile = Path.Combine(uniqueIssueDirName, currentReproFile); + File.WriteAllText(failFile, fileContents.ToString()); + Program.StartTrimmerForFile(failFile); } } diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 0ad7c2a..65487a4 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -35,7 +35,7 @@ public struct ReproDetails public class TestTrimmer { const int TRIMMER_RESET_COUNT = 10; - const int TRIMMER_TIMEOUT_IN_MINS = 15; + const int TRIMMER_TIMEOUT_IN_MINS = 30; const int TRIMMER_NEW_FOLDER_CHECK_IN_MINS = 5; const int SAVE_LKG_EVERY = 100; @@ -57,21 +57,22 @@ static int Main(string[] args) private static int Run(CommandLineOptions opts) { + int.TryParse(opts.ParentPid, out s_parentProcessId); + Task monitorTask = Task.Run(() => MonitorParentProcess()); + if (!string.IsNullOrEmpty(opts.ReproFile) && File.Exists(opts.ReproFile)) { return RunOne(opts); } - else + else if (!string.IsNullOrEmpty(opts.IssuesFolder) && Directory.Exists(opts.IssuesFolder)) { return RunMany(opts); } + throw new ArgumentException("Valid ReproFile or IssuesFolder needed."); } private static int RunMany(CommandLineOptions opts) { - int.TryParse(opts.ParentPid, out s_parentProcessId); - Task monitorTask = Task.Run(() => MonitorParentProcess()); - int uniqueId = 0; while (true) { @@ -96,8 +97,7 @@ private static int RunMany(CommandLineOptions opts) .OrderBy(fileInfo => fileInfo.Length) // Sort by file size .First().FullName; - TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, opts); - testTrimmer._issueFolder = uniqueFolder; + TestTrimmer testTrimmer = new TestTrimmer(testCaseToTrim, uniqueFolder, opts); testTrimmer.Trim(); testTrimmer.SaveRepro(); } @@ -105,28 +105,29 @@ private static int RunMany(CommandLineOptions opts) private static int RunOne(CommandLineOptions opts) { - TestTrimmer testTrimmer = new TestTrimmer(opts.ReproFile, opts); - testTrimmer._issueFolder = opts.IssuesFolder; + string issueFolder = Path.GetDirectoryName(opts.ReproFile); + TestTrimmer testTrimmer = new TestTrimmer(opts.ReproFile, issueFolder, opts); testTrimmer.Trim(); testTrimmer.SaveRepro(); return 0; } - public TestTrimmer(string testFileToTrim, CommandLineOptions opts) + public TestTrimmer(string testFileToTrim, string issueFolder, CommandLineOptions opts) { if (!System.IO.File.Exists(testFileToTrim)) { throw new Exception($"{testFileToTrim} doesn't exist."); } _opts = opts; - _compiler = new Compiler(opts.IssuesFolder); + _issueFolder = issueFolder; + _compiler = new Compiler(_issueFolder); _reproDetails = ParseReproFile(testFileToTrim); EEDriver driver = EEDriver.GetInstance(opts.CoreRunPath, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExecutionEngine.dll"), () => _reproDetails.envVars); - _testRunner = TestRunner.GetInstance(driver, opts.CoreRunPath, opts.IssuesFolder); + _testRunner = TestRunner.GetInstance(driver, opts.CoreRunPath); } /// @@ -612,7 +613,7 @@ public class CommandLineOptions [Option(shortName: 'p', longName: "ParentPid", Required = false, HelpText = "Antigen process id")] public string ParentPid { get; set; } - [Option(shortName: 'o', longName: "IssuesFolder", Required = true, HelpText = "Path to folder where trimmed issue will be copied.")] + [Option(shortName: 'o', longName: "IssuesFolder", Required = false, HelpText = "Path to folder where trimmed issue will be copied.")] public string IssuesFolder { get; set; } [Option(shortName: 'f', longName: "ReproFile", Required = false, HelpText = "Full path of the repro file.")] diff --git a/Utilities/TestRunner.cs b/Utilities/TestRunner.cs index 456c94f..0da3841 100644 --- a/Utilities/TestRunner.cs +++ b/Utilities/TestRunner.cs @@ -46,7 +46,6 @@ public class TestRunner private static TestRunner _testRunner; private readonly string _coreRun; - private readonly string _outputDirectory; private readonly EEDriver _driver; private static readonly string s_corelibPath = typeof(object).Assembly.Location; @@ -59,18 +58,17 @@ public class TestRunner MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location), }; - private TestRunner(EEDriver driver, string coreRun, string outputFolder) + private TestRunner(EEDriver driver, string coreRun) { _coreRun = coreRun; - _outputDirectory = outputFolder; _driver = driver; } - public static TestRunner GetInstance(EEDriver driver, string coreRun, string outputFolder) + public static TestRunner GetInstance(EEDriver driver, string coreRun) { if (_testRunner == null) { - _testRunner = new TestRunner(driver, coreRun, outputFolder); + _testRunner = new TestRunner(driver, coreRun); } return _testRunner; } From 8a50d5df8e1ad8a454c252c6f336394934afbb7c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 21:26:07 -0700 Subject: [PATCH 141/149] Misc changes --- Trimmer/TestTrimmer.cs | 5 +++++ Utilities/Compilation/CompileResult.cs | 6 +++--- Utilities/Compilation/Compiler.cs | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 65487a4..5398f0f 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -185,6 +185,11 @@ private ReproDetails ParseReproFile(string testFileToTrim) for (var i = fileContentLines.Length - 1; i >= 0; i--) { var line = fileContentLines[i].Trim(); + if (line.Contains("OutputMismatch") || line.Contains("Output mismatch")) + { + reproDetails.failureKind = TestResult.OutputMismatch; + return reproDetails; + } if (line.StartsWith("Debug: ")) { debugCode = int.Parse(line.Replace("Debug: ", string.Empty)); diff --git a/Utilities/Compilation/CompileResult.cs b/Utilities/Compilation/CompileResult.cs index e6a592d..cc5c224 100644 --- a/Utilities/Compilation/CompileResult.cs +++ b/Utilities/Compilation/CompileResult.cs @@ -19,7 +19,7 @@ public CompileResult(IEnumerable diagnostics) CompileWarnings = diagnostics.Where(diag => diag.Severity == DiagnosticSeverity.Warning); } - public CompileResult(string assemblyName, string assemblyFullPath, byte[] debugMs, byte[] releaseMs) + public CompileResult(string assemblyName, string assemblyFullPath, byte[]? debugMs, byte[]? releaseMs) { AssemblyName = assemblyName; AssemblyFullPath = assemblyFullPath; @@ -37,7 +37,7 @@ public CompileResult(Exception roslynException) public IEnumerable CompileErrors { get; } public IEnumerable CompileWarnings { get; } public string AssemblyFullPath { get; } - public byte[] DebugAssembly { get; } - public byte[] ReleaseAssembly { get; } + public byte[]? DebugAssembly { get; } + public byte[]? ReleaseAssembly { get; } } } diff --git a/Utilities/Compilation/Compiler.cs b/Utilities/Compilation/Compiler.cs index 2ef8f19..0825bc8 100644 --- a/Utilities/Compilation/Compiler.cs +++ b/Utilities/Compilation/Compiler.cs @@ -46,8 +46,12 @@ public Compiler(string outputDirectory) public CompileResult Compile(SyntaxTree programTree, string assemblyName) { - var debugBytes = CompileAndGetBytes(programTree, assemblyName, DebugCompileOptions); - var releaseBytes = CompileAndGetBytes(programTree, assemblyName, ReleaseCompileOptions); + byte[]? debugBytes = null, releaseBytes = null; + debugBytes = CompileAndGetBytes(programTree, assemblyName, DebugCompileOptions); + if (debugBytes != null) + { + releaseBytes = CompileAndGetBytes(programTree, assemblyName, ReleaseCompileOptions); + } return new CompileResult(assemblyName, null, debugBytes, releaseBytes); } @@ -89,10 +93,14 @@ private void SaveCompilationError(SyntaxTree tree, IEnumerable diagn fileContents.AppendLine(tree.GetRoot().NormalizeWhitespace().ToFullString()); fileContents.AppendLine("/*"); - fileContents.AppendLine($"Got {diagnostics.Count()} compiler error(s):"); var errorLines = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(diag => $"{diag.Location.GetLineSpan().StartLinePosition.Line}: {diag.GetMessage()}"); + fileContents.AppendLine($"Got {errorLines.Count()} compiler error(s):"); + foreach (var error in errorLines) + { + fileContents.AppendLine(error); + } var errorFile = Path.Combine(m_outputDirectory, $"{tree.FilePath}.error"); - File.WriteAllLines(errorFile, errorLines); + File.WriteAllText(errorFile, fileContents.ToString()); } } } From 26c1d67891a08f9d0c3a0cbf16a4f004e614fba4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 15 Aug 2024 21:32:38 -0700 Subject: [PATCH 142/149] Fixed trimmer issue --- Trimmer/TestTrimmer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Trimmer/TestTrimmer.cs b/Trimmer/TestTrimmer.cs index 5398f0f..ee3db30 100644 --- a/Trimmer/TestTrimmer.cs +++ b/Trimmer/TestTrimmer.cs @@ -212,7 +212,9 @@ public void Trim() var trimTask = Task.Run(TrimTree); trimTask.Wait(TimeSpan.FromMinutes(TRIMMER_TIMEOUT_IN_MINS)); } - catch { } + catch (Exception ex) { + Console.WriteLine("Timed out." + ex.Message); + } } /// @@ -497,6 +499,7 @@ private TestResult Verify(string iterId, SyntaxNode programRootNode/*, bool skip case RunOutcome.OutputMismatch: validationResult = TestResult.OutputMismatch; break; + case RunOutcome.OtherError: case RunOutcome.Timeout: case RunOutcome.Success: validationResult = TestResult.Pass; From 481b2a256d2373e0d57f4f5a9b20950d8f96ed2f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 2 Oct 2024 15:13:43 -0700 Subject: [PATCH 143/149] Add SYSLIB5003 assembly for Sve experiemental --- Antigen/AssemblyInfo.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Antigen/AssemblyInfo.cs diff --git a/Antigen/AssemblyInfo.cs b/Antigen/AssemblyInfo.cs new file mode 100644 index 0000000..6039835 --- /dev/null +++ b/Antigen/AssemblyInfo.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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; + + +using System.Runtime.Versioning; + +[assembly: Experimental("SYSLIB5003")] + From acc331f07b6c2724d10d74af1a8ebb707d657c3f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 8 Jan 2025 18:27:52 -0800 Subject: [PATCH 144/149] Make sure Antigen() stays in Trimmer --- Antigen/Helpers/PreGenerated.cs | 4 ++-- ExecutionEngine/Program.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Antigen/Helpers/PreGenerated.cs b/Antigen/Helpers/PreGenerated.cs index 74e3602..e77ac59 100644 --- a/Antigen/Helpers/PreGenerated.cs +++ b/Antigen/Helpers/PreGenerated.cs @@ -67,10 +67,10 @@ public static Statement StaticMethods StringBuilder staticMethodBuilder = new StringBuilder(); // Main method - staticMethodBuilder.AppendLine("public static void Main(string[] args) { "); + staticMethodBuilder.AppendLine("public static int Main(string[] args) { "); //staticMethodBuilder.AppendLine($"new {MainClassName}().Method0();"); //staticMethodBuilder.AppendLine("PrintLog();"); - staticMethodBuilder.AppendLine("Antigen();"); + staticMethodBuilder.AppendLine("return Antigen();"); staticMethodBuilder.AppendLine("}"); staticMethodBuilder.AppendLine("public static int Antigen() { "); diff --git a/ExecutionEngine/Program.cs b/ExecutionEngine/Program.cs index b0a58f3..2afb3fd 100644 --- a/ExecutionEngine/Program.cs +++ b/ExecutionEngine/Program.cs @@ -86,8 +86,8 @@ private static RunResult Run(byte[] assemblyBytes) { int hashCode; var assembly = s_loader.LoadFromBytes(assemblyBytes); - var methodInfo = assembly.GetType("TestClass").GetMethod("Antigen"); - var methodExec = methodInfo.CreateDelegate>(); + var methodInfo = assembly.GetType("TestClass").GetMethod("Main"); + var methodExec = methodInfo.CreateDelegate>(); // Adopted from Jakob's Fuzzlyn int threadID = Environment.CurrentManagedThreadId; @@ -104,7 +104,7 @@ void FirstChanceExceptionHandler(object sender, FirstChanceExceptionEventArgs ar try { - hashCode = methodExec(); + hashCode = methodExec(null); } catch { From 52810f6b71aeb522355f83f2466f2650681d4a02 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Apr 2025 12:53:48 -0700 Subject: [PATCH 145/149] Enable SVE --- Antigen/Config/ConfigOptions.cs | 2 +- Antigen/TestCase.cs | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Antigen/Config/ConfigOptions.cs b/Antigen/Config/ConfigOptions.cs index 3ca063c..39bc0e1 100644 --- a/Antigen/Config/ConfigOptions.cs +++ b/Antigen/Config/ConfigOptions.cs @@ -318,7 +318,7 @@ public class ConfigOptions /// /// AdvSimd methods probability /// - public double SveMethodsProbability = 0.0; + public double SveMethodsProbability = 0.65; /// /// Probability in which vector methods will be included. diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index 59a00d5..ee2d49a 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -93,21 +93,6 @@ public TestCase(int testId, RunOptions runOptions) Config = s_RunOptions.Configs[PRNG.Next(s_RunOptions.Configs.Count)]; ContainsVectorData = PRNG.Decide(Config.VectorDataProbability); - if (RuntimeInformation.OSArchitecture == Architecture.X64) - { - if (PRNG.Decide(Config.SveMethodsProbability)) - { - Config.UseSve = true; - ContainsVectorData = true; - } - } - // else - // { - // // local temporary change - // Config.UseSve = true; - // ContainsVectorData = true; - // } - AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; From 3f0546a860acd699d49839177b8b6f214a4811e8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Apr 2025 13:05:29 -0700 Subject: [PATCH 146/149] Set Config.UseSve --- Antigen/TestCase.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index ee2d49a..faa521f 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -91,7 +91,11 @@ public void IncreaseHitCount() public TestCase(int testId, RunOptions runOptions) { Config = s_RunOptions.Configs[PRNG.Next(s_RunOptions.Configs.Count)]; - ContainsVectorData = PRNG.Decide(Config.VectorDataProbability); + Config.UseSve = PRNG.Decide(Config.SveMethodsProbability); + if (Config.UseSve || PRNG.Decide(Config.VectorDataProbability)) + { + ContainsVectorData = true; + } AstUtils = new AstUtils(this, new ConfigOptions(), null); Name = "TestClass" + testId; From 8fb27abd1262227a9837f4ea1c97385c47605a6b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 30 Apr 2025 23:21:30 -0700 Subject: [PATCH 147/149] fix the CompileError for SVE --- Antigen/TestCase.cs | 2 +- Antigen/TestClass.cs | 2 +- Utilities/Compilation/Compiler.cs | 12 ++++++++++-- Utilities/TestRunner.cs | 9 --------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index faa521f..a9ca31b 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -91,7 +91,7 @@ public void IncreaseHitCount() public TestCase(int testId, RunOptions runOptions) { Config = s_RunOptions.Configs[PRNG.Next(s_RunOptions.Configs.Count)]; - Config.UseSve = PRNG.Decide(Config.SveMethodsProbability); + Config.UseSve = Sve.IsSupported && PRNG.Decide(Config.SveMethodsProbability); if (Config.UseSve || PRNG.Decide(Config.VectorDataProbability)) { ContainsVectorData = true; diff --git a/Antigen/TestClass.cs b/Antigen/TestClass.cs index f01d152..470e7c2 100644 --- a/Antigen/TestClass.cs +++ b/Antigen/TestClass.cs @@ -57,7 +57,7 @@ private void GenerateVectorMethods() bool addAvx = PRNG.Decide(TC.Config.AvxMethodsProbability); bool addSse = PRNG.Decide(TC.Config.SSEMethodsProbability); bool addTraditional = PRNG.Decide(TC.Config.TraditionalMethodsProbability); - bool addSve = TC.Config.UseSve || PRNG.Decide(TC.Config.SveMethodsProbability); + bool addSve = TC.Config.UseSve; bool addAdvsimd = TC.Config.UseSve || PRNG.Decide(TC.Config.AdvSimdMethodsProbability); // Register all the vector create methods diff --git a/Utilities/Compilation/Compiler.cs b/Utilities/Compilation/Compiler.cs index 0825bc8..645e310 100644 --- a/Utilities/Compilation/Compiler.cs +++ b/Utilities/Compilation/Compiler.cs @@ -20,12 +20,20 @@ public class Compiler private static readonly CSharpCompilationOptions ReleaseCompileOptions = new( OutputKind.ConsoleApplication, concurrentBuild: true, - optimizationLevel: OptimizationLevel.Release); + optimizationLevel: OptimizationLevel.Release, + specificDiagnosticOptions: new Dictionary + { + { "SYSLIB5003", ReportDiagnostic.Suppress } + }); private static readonly CSharpCompilationOptions DebugCompileOptions = new( OutputKind.ConsoleApplication, concurrentBuild: true, - optimizationLevel: OptimizationLevel.Debug); + optimizationLevel: OptimizationLevel.Debug, + specificDiagnosticOptions: new Dictionary + { + { "SYSLIB5003", ReportDiagnostic.Suppress } + }); private static readonly string s_corelibPath = typeof(object).Assembly.Location; private static readonly MetadataReference[] s_references = diff --git a/Utilities/TestRunner.cs b/Utilities/TestRunner.cs index 0da3841..ab611f4 100644 --- a/Utilities/TestRunner.cs +++ b/Utilities/TestRunner.cs @@ -35,15 +35,6 @@ public enum TestResult public class TestRunner { - internal static readonly CSharpCompilationOptions ReleaseCompileOptions = new ( - OutputKind.ConsoleApplication, - concurrentBuild: true, - optimizationLevel: OptimizationLevel.Release); - internal static readonly CSharpCompilationOptions DebugCompileOptions = new( - OutputKind.ConsoleApplication, - concurrentBuild: true, - optimizationLevel: OptimizationLevel.Debug); - private static TestRunner _testRunner; private readonly string _coreRun; private readonly EEDriver _driver; From 69d2547f91a233e6002001e5ca149e8661a4716a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 1 May 2025 10:58:08 -0700 Subject: [PATCH 148/149] fix build failure --- Antigen/TestCase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Antigen/TestCase.cs b/Antigen/TestCase.cs index a9ca31b..e333fb3 100644 --- a/Antigen/TestCase.cs +++ b/Antigen/TestCase.cs @@ -15,6 +15,7 @@ using Antigen.Execution; using static System.Net.Mime.MediaTypeNames; using System.Reflection; +using System.Runtime.Intrinsics.Arm; namespace Antigen { From 99674a2480a2c4f2399260007ef3742601052615 Mon Sep 17 00:00:00 2001 From: David Hartglass Date: Fri, 29 May 2026 15:23:18 -0700 Subject: [PATCH 149/149] Update jitutils README to point to Antigen --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72ead85..d5689b1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Current tools include: 4. [General tools](doc/tools.md): pmi 5. [Experimental tools](src/performance-explorer/README.md): performance-explorer 6. [BenchmarkDotNet Analysis](src/instructions-retired-explorer/README.md) +7. [Antigen](src/Antigen/README.md): contains a fork of [kunalspathak/Antigen](https://github.com/kunalspathak/Antigen), imported via `git subtree` from commit `69d2547f91a233e6002001e5ca149e8661a4716a`. ## Getting started