diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs index 6f4710561..cae3e8114 100644 --- a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs +++ b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs @@ -27,7 +27,7 @@ namespace ILCompiler private ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; private MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); - private SimdHelper _simdHelper; + protected SimdHelper _simdHelper; private TypeDesc[] _arrayOfTInterfaces; diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 02d073779..92c88b1c3 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -426,7 +426,7 @@ namespace ILCompiler.DependencyAnalysis { // Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them) Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any)); - + if (CompilationModuleGroup.ContainsType(type)) { return new AvailableType(this, type); diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCodegenCompilation.cs b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCodegenCompilation.cs index 048bff2c8..9b33858a2 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCodegenCompilation.cs @@ -128,6 +128,10 @@ namespace ILCompiler // If compilation fails, don't emit code for this method. It will be Jitted at runtime Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } + catch (RequiresRuntimeJitException ex) + { + Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); + } } } } diff --git a/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCompilerContext.cs b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCompilerContext.cs index e5064504c..e5a7b5d0a 100644 --- a/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCompilerContext.cs +++ b/src/ILCompiler.ReadyToRun/src/Compiler/ReadyToRunCompilerContext.cs @@ -14,12 +14,14 @@ namespace ILCompiler { private FieldLayoutAlgorithm _r2rFieldLayoutAlgorithm; private SystemObjectFieldLayoutAlgorithm _systemObjectFieldLayoutAlgorithm; + private VectorFieldLayoutAlgorithm _vectorFieldLayoutAlgorithm; public ReadyToRunCompilerContext(TargetDetails details, SharedGenericsMode genericsMode) : base(details, genericsMode) { _r2rFieldLayoutAlgorithm = new ReadyToRunMetadataFieldLayoutAlgorithm(); _systemObjectFieldLayoutAlgorithm = new SystemObjectFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm); + _vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm); } public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) @@ -30,10 +32,10 @@ namespace ILCompiler throw new NotImplementedException(); else if (type.IsRuntimeDeterminedType) throw new NotImplementedException(); - /* TODO else if (_simdHelper.IsVectorOfT(type)) - throw new NotImplementedException(); - */ + { + return _vectorFieldLayoutAlgorithm; + } else { Debug.Assert(_r2rFieldLayoutAlgorithm != null); @@ -70,5 +72,56 @@ namespace ILCompiler { return BaseTypeRuntimeInterfacesAlgorithm.Instance; } + + private class VectorFieldLayoutAlgorithm : FieldLayoutAlgorithm + { + private FieldLayoutAlgorithm _fallbackAlgorithm; + + public VectorFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm) + { + _fallbackAlgorithm = fallbackAlgorithm; + } + + public override bool ComputeContainsGCPointers(DefType type) + { + return _fallbackAlgorithm.ComputeContainsGCPointers(type); + } + + public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) + { + return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); + } + + public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) + { + List fieldsAndOffsets = new List(); + foreach (FieldDesc field in type.GetFields()) + { + if (!field.IsStatic) + { + fieldsAndOffsets.Add(new FieldAndOffset(field, LayoutInt.Indeterminate)); + } + } + ComputedInstanceFieldLayout instanceLayout = new ComputedInstanceFieldLayout() + { + FieldSize = LayoutInt.Indeterminate, + FieldAlignment = LayoutInt.Indeterminate, + ByteCountUnaligned = LayoutInt.Indeterminate, + ByteCountAlignment = LayoutInt.Indeterminate, + Offsets = fieldsAndOffsets.ToArray(), + }; + return instanceLayout; + } + + public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind) + { + return _fallbackAlgorithm.ComputeStaticFieldLayout(type, layoutKind); + } + + public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + { + return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); + } + } } } diff --git a/src/ILCompiler.ReadyToRun/src/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/ILCompiler.ReadyToRun/src/JitInterface/CorInfoImpl.ReadyToRun.cs index 8a3f59300..953d34aba 100644 --- a/src/ILCompiler.ReadyToRun/src/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/ILCompiler.ReadyToRun/src/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -28,6 +28,14 @@ namespace Internal.JitInterface } } + public class RequiresRuntimeJitException : Exception + { + public RequiresRuntimeJitException(object reason) + : base(reason.ToString()) + { + } + } + unsafe partial class CorInfoImpl { private const CORINFO_RUNTIME_ABI TargetABI = CORINFO_RUNTIME_ABI.CORINFO_CORECLR_ABI; diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 4dcca4a8b..73344103d 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -187,6 +187,13 @@ namespace Internal.JitInterface // Type system exceptions can be turned into code that throws the exception at runtime. _lastException.Throw(); } +#if READYTORUN + else if (_lastException.SourceException is RequiresRuntimeJitException) + { + // Runtime JIT requirement is not a cause for failure, we just mustn't JIT a particular method + _lastException.Throw(); + } +#endif else { // This is just a bug somewhere. @@ -1220,7 +1227,14 @@ namespace Internal.JitInterface private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); - return (uint)type.GetElementSize().AsInt; + LayoutInt classSize = type.GetElementSize(); +#if READYTORUN + if (classSize.IsIndeterminate) + { + throw new RequiresRuntimeJitException(type); + } +#endif + return (uint)classSize.AsInt; } private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) diff --git a/tests/src/Simple/ReadyToRunUnit/Program.cs b/tests/src/Simple/ReadyToRunUnit/Program.cs index 2e167f965..24d2e5384 100644 --- a/tests/src/Simple/ReadyToRunUnit/Program.cs +++ b/tests/src/Simple/ReadyToRunUnit/Program.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Numerics; using System.Text; internal class ClassWithStatic @@ -627,6 +628,27 @@ internal class Program return result; } + private static bool VectorTestOf(T value1, T value2, T sum) + where T : struct + { + Console.WriteLine("Constructing vector of {0}", value1); + Vector vector1 = new Vector(value1); + Console.WriteLine("Vector[0] = {0}", vector1[0]); + Vector vector2 = new Vector(value2); + Vector vectorSum = vector1 + vector2; + Console.WriteLine("Vector sum = {0}, {1} expected", vectorSum[0], sum); + return vectorSum[0].Equals(sum); + } + + private static bool VectorTest() + { + bool success = true; + success &= VectorTestOf(10, 20, 30); + success &= VectorTestOf(15.0f, 30.0f, 45.0f); + success &= VectorTestOf(50.0, 100.0, 150.0); + return success; + } + public static int Main(string[] args) { if (args.Length > 0) @@ -671,6 +693,7 @@ internal class Program RunTest("ThisObjGenericLookupTest", ThisObjGenericLookupTest()); RunTest("ClassParamGenericLookupTest", ClassParamGenericLookupTest()); RunTest("MethodParamGenericLookupTest", MethodParamGenericLookupTest()); + RunTest("VectorTest", VectorTest()); Console.WriteLine($@"{_passedTests.Count} tests pass:"); foreach (string testName in _passedTests) diff --git a/tests/src/Simple/ReadyToRunUnit/methodWhiteList.txt b/tests/src/Simple/ReadyToRunUnit/methodWhiteList.txt index 09c418e80..e6d73bf6e 100644 --- a/tests/src/Simple/ReadyToRunUnit/methodWhiteList.txt +++ b/tests/src/Simple/ReadyToRunUnit/methodWhiteList.txt @@ -1,5 +1,6 @@ Program..cctor() +Program.VectorTestOf(!!0,!!0,!!0) Program+DisposeStruct..cctor() Program+DisposeClass.Dispose() Program+DisposeClass..cctor() -ClassWithStatic..cctor() \ No newline at end of file +ClassWithStatic..cctor()