diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index faf5ab5bd7b747..a7c65283f91893 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -573,6 +573,7 @@ public static bool ShouldCodeNotBeCompiledIntoFinalImage(InstructionSetSupport i var handle = ecmaMethod.Handle; List compExactlyDependsOnList = null; + bool hasCompHasFallback = false; foreach (var attributeHandle in metadataReader.GetMethodDefinition(handle).GetCustomAttributes()) { @@ -606,35 +607,41 @@ public static bool ShouldCodeNotBeCompiledIntoFinalImage(InstructionSetSupport i compExactlyDependsOnList.Add(typeForBypass); } } + else if (metadataReader.StringComparer.Equals(nameHandle, "CompHasFallbackAttribute")) + { + hasCompHasFallback = true; + } } } if (compExactlyDependsOnList != null && compExactlyDependsOnList.Count > 0) { - // Default to true, and set to false if at least one of the types is actually supported in the current environment, and none of the - // intrinsic types are in an opportunistic state. - bool doBypass = true; + bool anySupported = false; foreach (var intrinsicType in compExactlyDependsOnList) { InstructionSet instructionSet = InstructionSetParser.LookupPlatformIntrinsicInstructionSet(intrinsicType.Context.Target.Architecture, intrinsicType); - if (instructionSet == InstructionSet.ILLEGAL) - { - // This instruction set isn't supported on the current platform at all. - continue; - } - if (instructionSetSupport.IsInstructionSetSupported(instructionSet) || instructionSetSupport.IsInstructionSetExplicitlyUnsupported(instructionSet)) - { - doBypass = false; - } - else + // If the instruction set is ILLEGAL, it means it is never supported by the current architecture so the behavior at runtime is known + if (instructionSet != InstructionSet.ILLEGAL) { - // If we reach here this is an instruction set generally supported on this platform, but we don't know what the behavior will be at runtime - return true; + if (instructionSetSupport.IsInstructionSetSupported(instructionSet)) + { + anySupported = true; + } + else if (!instructionSetSupport.IsInstructionSetExplicitlyUnsupported(instructionSet)) + { + // If we reach here this is an instruction set generally supported on this platform, but we don't know what the behavior will be at runtime + return true; + } } } - return doBypass; + if (!anySupported && !hasCompHasFallback) + { + // If none of the instruction sets are supported (all are either illegal or explicitly unsupported), + // skip compilation unless the method has a functional fallback path + return true; + } } // No reason to bypass compilation and code generation. diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index c744f85d3e05ce..6308788f0d0789 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -837,6 +837,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompHasFallbackAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompHasFallbackAttribute.cs new file mode 100644 index 00000000000000..9ce5344c277d86 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompHasFallbackAttribute.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Runtime.CompilerServices +{ + // Use this attribute alongside CompExactlyDependsOnAttribute to indicate that a method has + // a functional fallback path and should still be compiled into the Ready2Run image even when + // none of the CompExactlyDependsOn instruction sets are supported. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] +#if MONO + [Conditional("unnecessary")] // Mono doesn't use Ready2Run so we can remove this attribute to reduce size +#endif + internal sealed class CompHasFallbackAttribute : Attribute + { + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs index 73de2d970c626d..ecbbea5f8744fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs @@ -301,6 +301,7 @@ internal interface IRuntimeConst /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [CompExactlyDependsOn(typeof(Ssse3))] + [CompHasFallback] internal static Vector128 ShuffleNativeModified(Vector128 vector, Vector128 indices) { if (Ssse3.IsSupported) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs index cdec5bb675b312..6c84d46a1ab6e0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs @@ -1632,6 +1632,7 @@ private static bool AllCharsInVectorAreAscii(Vector128 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] [CompExactlyDependsOn(typeof(Avx))] + [CompHasFallback] private static bool AllCharsInVectorAreAscii(Vector256 vector) where T : unmanaged {