diff --git a/src/Antigen/Antigen/Antigen.cs b/src/Antigen/Antigen/Antigen.cs
index e45bdc72..725cbe71 100644
--- a/src/Antigen/Antigen/Antigen.cs
+++ b/src/Antigen/Antigen/Antigen.cs
@@ -9,6 +9,7 @@
using Utils;
using System.Linq;
using System.Runtime.CompilerServices;
+using Antigen.Compilation;
using Antigen.Execution;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -89,8 +90,15 @@ internal static int Run(AntigenRootCommand command)
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);
- // Generate vector methods
- VectorHelpers.RecordVectorMethods();
+ // Generate vector methods. The flag must be set before recording, because the
+ // method pool is built once and reused for every test case. The pool and the
+ // compiler both read CORE_ROOT so that the API surface Antigen generates against
+ // is the same one the tests will execute against.
+ string coreRootDirectory = Path.GetDirectoryName(Path.GetFullPath(s_runOptions.CoreRun));
+ Compiler.SetReferenceDirectory(coreRootDirectory);
+ VectorHelpers.AllowFloatToIntegralReinterpret =
+ result.GetValue(command.AllowFloatToIntegralReinterpret);
+ VectorHelpers.RecordVectorMethods(coreRootDirectory);
Parallel.For(0, 4, (p) => RunTest());
Console.WriteLine($"Executed {s_testId} test cases.");
diff --git a/src/Antigen/Antigen/Antigen.csproj b/src/Antigen/Antigen/Antigen.csproj
index c72d3a78..854e8caa 100644
--- a/src/Antigen/Antigen/Antigen.csproj
+++ b/src/Antigen/Antigen/Antigen.csproj
@@ -10,6 +10,7 @@
+
diff --git a/src/Antigen/Antigen/AntigenRootCommand.cs b/src/Antigen/Antigen/AntigenRootCommand.cs
index 74b0b285..7deb6009 100644
--- a/src/Antigen/Antigen/AntigenRootCommand.cs
+++ b/src/Antigen/Antigen/AntigenRootCommand.cs
@@ -17,6 +17,8 @@ internal sealed class AntigenRootCommand : RootCommand
new("--NumTestCases", "-n") { Description = "Number of test cases to execute. By default, 1000." };
public Option RunDuration { get; } =
new("--RunDuration", "-d") { Description = "Duration in minutes to run. By default until NumTestCases, but if Duration is given, will override the NumTestCases." };
+ public Option AllowFloatToIntegralReinterpret { get; } =
+ new("--AllowFloatToIntegralReinterpret") { Description = "Allow reinterpret-casting floating point vectors to integral types (for example, Vector128.AsInt32()). Can cause false positives due to differing NaN representations." };
public ParseResult Result { get; private set; }
@@ -26,6 +28,7 @@ public AntigenRootCommand(string[] args) : base("Antigen JIT fuzzer")
Options.Add(IssuesFolder);
Options.Add(NumTestCases);
Options.Add(RunDuration);
+ Options.Add(AllowFloatToIntegralReinterpret);
SetAction(result =>
{
diff --git a/src/Antigen/Antigen/Expressions/ConstantValue.cs b/src/Antigen/Antigen/Expressions/ConstantValue.cs
index ddb88b19..c2fb4f85 100644
--- a/src/Antigen/Antigen/Expressions/ConstantValue.cs
+++ b/src/Antigen/Antigen/Expressions/ConstantValue.cs
@@ -20,6 +20,13 @@ public class ConstantValue : Expression
{ "Vector4", new List() { "One", "Zero", "UnitW", "UnitX", "UnitY", "UnitZ" } },
};
+ // Reduce the prevelence of vector-of-floats.AllBitsSet(), as NaN's tend to pollute
+ // otherwise interesting computations
+ private const double FloatingPointAllBitsSetProbability = 0.05;
+ private const double IntegralAllBitsSetProbability = 0.5;
+
+ private static readonly List s_nonNaNVectorConstants = new List() { "Zero", "One", "Indices" };
+
protected ConstantValue(Tree.ValueType valueType, string value) : base(null)
{
if (valueType.PrimitiveType == Primitive.Char)
@@ -87,7 +94,13 @@ public static ConstantValue GetConstantValue(Tree.ValueType literalType, IList> 8); h *= 1099511628211UL;");
+ staticMethodBuilder.AppendLine("}");
+ staticMethodBuilder.AppendLine("return (int)(h ^ (h >> 32));");
staticMethodBuilder.AppendLine("}");
// Log method
diff --git a/src/Antigen/Antigen/Helpers/VectorHelpers.cs b/src/Antigen/Antigen/Helpers/VectorHelpers.cs
index 8f021866..b1a6b686 100644
--- a/src/Antigen/Antigen/Helpers/VectorHelpers.cs
+++ b/src/Antigen/Antigen/Helpers/VectorHelpers.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
@@ -19,11 +20,24 @@ namespace Antigen
{
public class VectorHelpers
{
- 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 static readonly string[] s_vectorGenericArgNames = new[]
+ {
+ "System.Byte", "System.SByte", "System.Int16", "System.UInt16", "System.Int32",
+ "System.UInt32", "System.Int64", "System.UInt64", "System.Single", "System.Double"
+ };
+
+ private static List s_vectorGenericArgs = null;
private static List s_allVectorMethods = null;
private static List s_allVectorTypes = null;
+ // When set, build the method pool by reading CORE_ROOT rather than by reflecting over
+ // Antigen's own runtime.
+ private static MetadataLoadContext s_metadataContext = null;
+ private static Assembly s_coreLib = null;
+
+ // Allow float-to-int reinterpret casts (Vector.As) in the method pool
+ public static bool AllowFloatToIntegralReinterpret = false;
+
public static List GetAllVectorMethods()
{
Debug.Assert(s_allVectorMethods != null);
@@ -138,7 +152,13 @@ private static void RecordVectorTypes()
];
}
- public static void RecordVectorMethods()
+ ///
+ /// Build the method pool. When is supplied, the
+ /// pool is read from CORE_ROOT's assemblies (the framework the generated tests will
+ /// actually execute against). When null, falls back to reflecting over Antigen's own
+ /// runtime, which is the historical behavior.
+ ///
+ public static void RecordVectorMethods(string coreRootDirectory = null)
{
Debug.Assert(s_allVectorTypes == null);
@@ -147,63 +167,286 @@ public static void RecordVectorMethods()
return;
}
+ InitializeMetadataContext(coreRootDirectory);
+
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));
+ s_vectorGenericArgs = s_vectorGenericArgNames.Select(ResolveType).Where(t => t != null).ToList();
+ if (s_vectorGenericArgs.Count != s_vectorGenericArgNames.Length)
+ {
+ throw new InvalidOperationException(
+ $"Could not resolve the primitive types used to instantiate generic vector methods. " +
+ $"Resolved {s_vectorGenericArgs.Count} of {s_vectorGenericArgNames.Length}.");
+ }
+
+ RecordIntrinsicMethods("System.Numerics.Vector", "Vector");
+ RecordIntrinsicMethods("System.Numerics.Vector2", "Vector2");
+ RecordIntrinsicMethods("System.Numerics.Vector3", "Vector3");
+ RecordIntrinsicMethods("System.Numerics.Vector4", "Vector4");
+ RecordVectorCtors("System.Numerics.Vector2");
+ RecordVectorCtors("System.Numerics.Vector3");
+ RecordVectorCtors("System.Numerics.Vector4");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Vector64", "Vector64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Vector128", "Vector128");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Vector256", "Vector256");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Vector512", "Vector512");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Arm.AdvSimd", "AdvSimd");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Arm.AdvSimd+Arm64", "AdvSimd.Arm64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.Arm.Sve", "Sve");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Aes", "Aes");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Bmi1", "Bmi1");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Bmi1+X64", "Bmi1.X64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Bmi2", "Bmi2");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Bmi2+X64", "Bmi2.X64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Fma", "Fma");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Lzcnt", "Lzcnt");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Lzcnt+X64", "Lzcnt.X64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Pclmulqdq", "Pclmulqdq");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Popcnt", "Popcnt");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Popcnt+X64", "Popcnt.X64");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx", "Avx");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx2", "Avx2");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx512BW", "Avx512BW");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx512CD", "Avx512CD");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx512DQ", "Avx512DQ");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx512F", "Avx512F");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Avx512Vbmi", "Avx512Vbmi");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse", "Sse");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse2", "Sse2");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse3", "Sse3");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse41", "Sse41");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse42", "Sse42");
+ RecordIntrinsicMethods("System.Runtime.Intrinsics.X86.Sse", "Sse");
}
- private static bool ShouldSkipVectorMethod(string fullMethodName)
+ ///
+ /// Open CORE_ROOT for metadata-only inspection. Nothing here is ever executed, so the
+ /// assemblies do not need to match the runtime Antigen is running on.
+ ///
+ private static void InitializeMetadataContext(string coreRootDirectory)
{
+ if (string.IsNullOrEmpty(coreRootDirectory))
+ {
+ return;
+ }
+
+ string coreLibPath = Path.Combine(coreRootDirectory, "System.Private.CoreLib.dll");
+ if (!File.Exists(coreLibPath))
+ {
+ Console.WriteLine($"WARNING: {coreLibPath} not found; falling back to Antigen's own framework " +
+ $"for the method pool. Generated tests may use APIs that do not exist in CORE_ROOT.");
+ return;
+ }
+
+ s_metadataContext = new MetadataLoadContext(
+ new PathAssemblyResolver(Directory.GetFiles(coreRootDirectory, "*.dll")));
+ s_coreLib = s_metadataContext.LoadFromAssemblyPath(coreLibPath);
+ }
+
+ ///
+ /// Resolve a type by full metadata name from CORE_ROOT when available, otherwise from
+ /// Antigen's own runtime.
+ ///
+ private static Type ResolveType(string fullName)
+ {
+ if (s_coreLib != null)
+ {
+ Type fromCoreLib = s_coreLib.GetType(fullName);
+ if (fromCoreLib != null)
+ {
+ return fromCoreLib;
+ }
+
+ foreach (var assembly in s_metadataContext.GetAssemblies())
+ {
+ Type candidate = assembly.GetType(fullName);
+ if (candidate != null)
+ {
+ return candidate;
+ }
+ }
+
+ Console.WriteLine($"WARNING: '{fullName}' was not found in CORE_ROOT's " +
+ $"System.Private.CoreLib (searched {s_metadataContext.GetAssemblies().Count()} " +
+ $"loaded assemblies). Any methods on it will be missing from the pool.");
+ return null;
+ }
+
+ Type fromOwnRuntime = Type.GetType(fullName);
+ if (fromOwnRuntime == null)
+ {
+ Console.WriteLine($"WARNING: '{fullName}' was not found in Antigen's own framework. " +
+ $"Any methods on it will be missing from the pool.");
+ }
+
+ return fromOwnRuntime;
+ }
+
+ ///
+ /// True if every generic argument of appears somewhere in its
+ /// parameter list, and so can be inferred by the C# compiler at a call site that does not
+ /// spell out type arguments.
+ ///
+ private static bool CanInferGenericArguments(MethodInfo method)
+ {
+ var genericArguments = method.GetGenericArguments();
+ var parameters = method.GetParameters();
+
+ foreach (var genericArgument in genericArguments)
+ {
+ bool found = false;
+ foreach (var parameter in parameters)
+ {
+ if (MentionsType(parameter.ParameterType, genericArgument))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool MentionsType(Type type, Type sought)
+ {
+ if (type.IsGenericParameter)
+ {
+ return type.Name == sought.Name;
+ }
+
+ if (type.HasElementType)
+ {
+ return MentionsType(type.GetElementType(), sought);
+ }
+
+ if (type.IsGenericType)
+ {
+ foreach (var argument in type.GetGenericArguments())
+ {
+ if (MentionsType(argument, sought))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static bool ShouldSkipVectorMethod(string fullMethodName) {
// We do not support these types, so ignore these methods.
+ // Need both "Byref" and "&" as MethodInfo.ToString() can render these differently
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("&") ||
fullMethodName.Contains("Numerics.Plane") || fullMethodName.Contains("Divide") ||
/*fullMethodName.Contains("SveMaskPattern") ||*/ fullMethodName.Contains("SvePrefetchType") ||
fullMethodName.Contains("FloatComparisonMode") || fullMethodName.Contains("FloatRoundingMode") ||
fullMethodName.Contains("MidpointRounding") || fullMethodName.Contains("Unsafe");
}
+ // Look for reinterpret casts away from a floating point element type using "Vector.As",
+ // and for the "*WhereAllBitsSet" bit tests applied to a floating point vector.
+ // A pretty common source of false positives is
+ // some_fp_vector -> Vector.As -> some_other_vector -> print_bits
+ // The JIT is permitted to choose different bitwise representations for NaN
+ private static bool IsFloatToIntegralReinterpretation(MethodInfo method)
+ {
+ if (IsAllBitsSetTestOnFloat(method))
+ {
+ return true;
+ }
+
+ if (!method.Name.StartsWith("As", StringComparison.Ordinal) ||
+ method.Name.Equals("Asin", StringComparison.Ordinal))
+ {
+ return false;
+ }
+
+ var parameters = method.GetParameters();
+ if (parameters.Length != 1)
+ {
+ return false;
+ }
+
+ return IsFloatingPointElementVector(parameters[0].ParameterType);
+ }
+
+ // Same issue with "*WhereAllBitsSet" family (CountWhereAllBitsSet, AnyWhereAllBitsSet, ...)
+ // As for Vector.As*
+ private static bool IsAllBitsSetTestOnFloat(MethodInfo method)
+ {
+ if (!method.Name.EndsWith("WhereAllBitsSet", StringComparison.Ordinal))
+ {
+ return false;
+ }
+
+ foreach (var parameter in method.GetParameters())
+ {
+ if (IsFloatingPointElementVector(parameter.ParameterType))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns the element type of a closed generic vector type, or null if the type is not
+ /// one (Vector2/Vector3/Vector4 and open generics both return null).
+ ///
+ private static Type VectorElementType(Type type)
+ {
+ if (!type.IsGenericType || type.ContainsGenericParameters)
+ {
+ return null;
+ }
+
+ var genericArgs = type.GetGenericArguments();
+ return genericArgs.Length == 1 ? genericArgs[0] : null;
+ }
+
+ private static bool IsFloatingPointElementVector(Type type)
+ {
+ var elementType = VectorElementType(type);
+ // Compared by name, not by typeof(): when the pool is built from CORE_ROOT metadata
+ // these Types come from a MetadataLoadContext, so reference equality against the
+ // runtime's typeof(float) is always false and this filter would silently stop working.
+ return elementType != null &&
+ (elementType.FullName == "System.Single" || elementType.FullName == "System.Double");
+ }
+
+ private static void RecordIntrinsicMethods(string typeFullName, string vectorTypeName)
+ {
+ Type resolved = ResolveType(typeFullName);
+ if (resolved == null)
+ {
+ // Expected for intrinsic classes absent from this framework version.
+ return;
+ }
+
+ RecordIntrinsicMethods(resolved, vectorTypeName);
+ }
+
+ private static void RecordVectorCtors(string typeFullName)
+ {
+ Type resolved = ResolveType(typeFullName);
+ if (resolved != null)
+ {
+ RecordVectorCtors(resolved);
+ }
+ }
+
///
/// Record the vector methods as well as the ones that creates the Vector.
/// Applicable for Vector64, Vector128, Vector256, Vector512.
@@ -234,6 +477,11 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam
continue;
}
+ if (!AllowFloatToIntegralReinterpret && IsFloatToIntegralReinterpretation(method))
+ {
+ continue;
+ }
+
s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, method));
nonGenericAdded.Add(method.Name);
}
@@ -261,12 +509,25 @@ private static void RecordIntrinsicMethods(Type vectorType, string vectorTypeNam
continue;
}
+ if (!CanInferGenericArguments(method))
+ {
+ // Something like "Vector128.Pi()" with no args breaks our type inference,
+ // leave these out
+ continue;
+ }
+
if (method.GetGenericArguments().Count() == 1)
{
// Only instantiate generic single argument methods
foreach (var genericArgument in s_vectorGenericArgs)
{
var genericInitVectorMethod = method.MakeGenericMethod(genericArgument);
+
+ if (!AllowFloatToIntegralReinterpret && IsFloatToIntegralReinterpretation(genericInitVectorMethod))
+ {
+ continue;
+ }
+
s_allVectorMethods.Add(CreateMethodSignature(vectorTypeName, genericInitVectorMethod));
}
}
diff --git a/src/Antigen/Antigen/TestCase.cs b/src/Antigen/Antigen/TestCase.cs
index e333fb36..a8abdb71 100644
--- a/src/Antigen/Antigen/TestCase.cs
+++ b/src/Antigen/Antigen/TestCase.cs
@@ -38,7 +38,6 @@ public enum CompilationType
"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;
@@ -177,8 +176,12 @@ public TestResult Verify()
{
return TestResult.Overflow;
}
+
+ // Known error that we have no specific bucket for (e.g. the JIT
+ // assert in _knownDiffs). Report it, but do not save a repro:
+ // it is an already-filed issue.
+ return TestResult.OtherError;
}
- return TestResult.OtherError;
}
var parsedError = RslnUtilities.ParseAssertionError(errorMessage);
parsedError = parsedError ?? errorMessage;
diff --git a/src/Antigen/Antigen/TestMethod.cs b/src/Antigen/Antigen/TestMethod.cs
index fc41d567..f2d2237e 100644
--- a/src/Antigen/Antigen/TestMethod.cs
+++ b/src/Antigen/Antigen/TestMethod.cs
@@ -925,12 +925,12 @@ private Expression MethodCallHelper(MethodSignature methodSig, int depth)
{
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)
+ // For GetElement/WithElement, the index must stay below the element count.
VectorType targetVectorType = methodSig.Parameters[0].ParamType.VectorType;
ConstantValue elementCountExpr;
if (Tree.ValueType.GetElementCount(targetVectorType) == 1)
{
- elementCountExpr = ConstantValue.GetConstantValue(1);
+ elementCountExpr = ConstantValue.GetConstantValue(0);
}
else
{
diff --git a/src/Antigen/Antigen/Tree/Types.cs b/src/Antigen/Antigen/Tree/Types.cs
index 0fbef450..13bf6281 100644
--- a/src/Antigen/Antigen/Tree/Types.cs
+++ b/src/Antigen/Antigen/Tree/Types.cs
@@ -118,6 +118,34 @@ public bool IsVectorNumerics()
return false;
}
+ public bool HasFloatingPointElement()
+ {
+ if (!IsVectorType)
+ {
+ return false;
+ }
+
+ switch (VectorType)
+ {
+ case VectorType.Vector64_Float:
+ case VectorType.Vector64_Double:
+ case VectorType.Vector128_Float:
+ case VectorType.Vector128_Double:
+ case VectorType.Vector256_Float:
+ case VectorType.Vector256_Double:
+ case VectorType.Vector512_Float:
+ case VectorType.Vector512_Double:
+ case VectorType.Vector_Float:
+ case VectorType.Vector_Double:
+ case VectorType.Vector2:
+ case VectorType.Vector3:
+ case VectorType.Vector4:
+ return true;
+ default:
+ return false;
+ }
+ }
+
public bool IsVectorTIntrinsics()
{
if (IsVectorType)
diff --git a/src/Antigen/ExecutionEngine/Program.cs b/src/Antigen/ExecutionEngine/Program.cs
index 76e15dc9..01175e0b 100644
--- a/src/Antigen/ExecutionEngine/Program.cs
+++ b/src/Antigen/ExecutionEngine/Program.cs
@@ -81,7 +81,20 @@ static async Task Main(string[] args)
///
///
///
+ // As in Fuzzlyn, run generated code on a dedicated large stack thread.
+ // Generated code has deep call trees and frequently stack overlfows, otherwise
+ private const int GeneratedCodeStackSizeBytes = 64 * 1024 * 1024;
+
private static RunResult Run(byte[] assemblyBytes)
+ {
+ RunResult result = default;
+ Thread runnerThread = new(() => result = RunOnCurrentThread(assemblyBytes), GeneratedCodeStackSizeBytes);
+ runnerThread.Start();
+ runnerThread.Join();
+ return result;
+ }
+
+ private static RunResult RunOnCurrentThread(byte[] assemblyBytes)
{
int hashCode;
var assembly = s_loader.LoadFromBytes(assemblyBytes);
diff --git a/src/Antigen/Trimmer/TestTrimmer.cs b/src/Antigen/Trimmer/TestTrimmer.cs
index 2d863409..9f1acae0 100644
--- a/src/Antigen/Trimmer/TestTrimmer.cs
+++ b/src/Antigen/Trimmer/TestTrimmer.cs
@@ -70,6 +70,11 @@ internal static int Run(TrimmerRootCommand command)
AltJitMethodName = result.GetValue(command.AltJitMethodName),
};
+ // Trimmer runs in a separate process, so it does not inherit Antigen's
+ // process-local compiler configuration.
+ string coreRootDirectory = Path.GetDirectoryName(Path.GetFullPath(opts.CoreRunPath));
+ Compiler.SetReferenceDirectory(coreRootDirectory);
+
int.TryParse(opts.ParentPid, out s_parentProcessId);
Task monitorTask = Task.Run(() => MonitorParentProcess());
diff --git a/src/Antigen/Utilities/Compilation/Compiler.cs b/src/Antigen/Utilities/Compilation/Compiler.cs
index ded1ce22..411803ef 100644
--- a/src/Antigen/Utilities/Compilation/Compiler.cs
+++ b/src/Antigen/Utilities/Compilation/Compiler.cs
@@ -35,15 +35,32 @@ public class Compiler
{ "SYSLIB5003", ReportDiagnostic.Suppress }
});
- 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),
- };
+ // Generated tests must compile against CORE_ROOT, not Antigen's own framework, because
+ // they execute under CORE_ROOT's corerun. Initialize to Antigen's framework to preserve
+ // the previous behavior for callers that do not configure a reference directory.
+ private static MetadataReference[] s_references =
+ CreateReferences(Path.GetDirectoryName(typeof(object).Assembly.Location) ??
+ throw new InvalidOperationException("Could not locate Antigen's framework directory."));
+
+ ///
+ /// Point compilation at CORE_ROOT. Must be called before the first Compile().
+ ///
+ public static void SetReferenceDirectory(string referenceDirectory)
+ {
+ s_references = CreateReferences(referenceDirectory);
+ }
+
+ private static MetadataReference[] CreateReferences(string referenceDirectory)
+ {
+ return new MetadataReference[]
+ {
+ MetadataReference.CreateFromFile(Path.Combine(referenceDirectory, "System.Private.CoreLib.dll")),
+ MetadataReference.CreateFromFile(Path.Combine(referenceDirectory, "System.Console.dll")),
+ MetadataReference.CreateFromFile(Path.Combine(referenceDirectory, "System.Runtime.dll")),
+ MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location),
+ MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location),
+ };
+ }
private readonly string m_outputDirectory;