Skip to content

Commit

Permalink
Make it possible to preinitialize HW intrinsic IsSupported (#92666)
Browse files Browse the repository at this point in the history
* Move the IL rewriting for HW intrinsics `IsSuported` calls to `ILProvider` from `RyuJitCompilation`
* Also rewrite constant true/false
  • Loading branch information
MichalStrehovsky authored Sep 27, 2023
1 parent 43f236d commit d1d6a6b
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using Internal.IL;
using Internal.IL.Stubs;
using Internal.JitInterface;
using Internal.TypeSystem;

namespace ILCompiler
{
public sealed class HardwareIntrinsicILProvider : ILProvider
{
private readonly InstructionSetSupport _isaSupport;
private readonly TypeSystemContext _context;
private readonly FieldDesc _isSupportedField;
private readonly ILProvider _nestedProvider;
private readonly Dictionary<string, InstructionSet> _instructionSetMap;

public HardwareIntrinsicILProvider(InstructionSetSupport isaSupport, FieldDesc isSupportedField, ILProvider nestedProvider)
{
_isaSupport = isaSupport;
_context = isSupportedField.Context;
_isSupportedField = isSupportedField;
_nestedProvider = nestedProvider;

_instructionSetMap = new Dictionary<string, InstructionSet>();
foreach (var instructionSetInfo in InstructionSetFlags.ArchitectureToValidInstructionSets(_context.Target.Architecture))
{
if (instructionSetInfo.ManagedName != "")
_instructionSetMap.Add(instructionSetInfo.ManagedName, instructionSetInfo.InstructionSet);
}
}

public override MethodIL GetMethodIL(MethodDesc method)
{
TypeDesc owningType = method.OwningType;
string intrinsicId = InstructionSetSupport.GetHardwareIntrinsicId(_context.Target.Architecture, owningType);
if (!string.IsNullOrEmpty(intrinsicId)
&& HardwareIntrinsicHelpers.IsIsSupportedMethod(method))
{
InstructionSet instructionSet = _instructionSetMap[intrinsicId];

bool isSupported = _isaSupport.IsInstructionSetSupported(instructionSet);
bool isOptimisticallySupported = _isaSupport.OptimisticFlags.HasInstructionSet(instructionSet);

// If this is an instruction set that is optimistically supported, but is not one of the
// intrinsics that are known to be always available, emit IL that checks the support level
// at runtime.
if (!isSupported && isOptimisticallySupported)
{
return HardwareIntrinsicHelpers.EmitIsSupportedIL(method, _isSupportedField, instructionSet);
}
else
{
ILOpcode flag = isSupported ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0;
return new ILStubMethodIL(method,
new byte[] { (byte)flag, (byte)ILOpcode.ret },
Array.Empty<LocalVariableDefinition>(),
null);
}
}

return _nestedProvider.GetMethodIL(method);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@
<Compile Include="Compiler\GeneratingMetadataManager.cs" />
<Compile Include="Compiler\GenericRootProvider.cs" />
<Compile Include="Compiler\HardwareIntrinsicHelpers.Aot.cs" />
<Compile Include="Compiler\HardwareIntrinsicILProvider.cs" />
<Compile Include="Compiler\IInliningPolicy.cs" />
<Compile Include="Compiler\Logging\NativeAotFatalErrorException.cs" />
<Compile Include="Compiler\ManifestResourceBlockingPolicy.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ public sealed class RyuJitCompilation : Compilation
{
private readonly ConditionalWeakTable<Thread, CorInfoImpl> _corinfos = new ConditionalWeakTable<Thread, CorInfoImpl>();
internal readonly RyuJitCompilationOptions _compilationOptions;
private readonly ExternSymbolMappedField _hardwareIntrinsicFlags;
private readonly Dictionary<string, InstructionSet> _instructionSetMap;
private readonly ProfileDataManager _profileDataManager;
private readonly MethodImportationErrorProvider _methodImportationErrorProvider;
private readonly int _parallelism;
Expand All @@ -47,16 +45,8 @@ internal RyuJitCompilation(
: base(dependencyGraph, nodeFactory, roots, ilProvider, debugInformationProvider, devirtualizationManager, inliningPolicy, logger)
{
_compilationOptions = options;
_hardwareIntrinsicFlags = new ExternSymbolMappedField(nodeFactory.TypeSystemContext.GetWellKnownType(WellKnownType.Int32), "g_cpuFeatures");
InstructionSetSupport = instructionSetSupport;

_instructionSetMap = new Dictionary<string, InstructionSet>();
foreach (var instructionSetInfo in InstructionSetFlags.ArchitectureToValidInstructionSets(TypeSystemContext.Target.Architecture))
{
if (instructionSetInfo.ManagedName != "")
_instructionSetMap.Add(instructionSetInfo.ManagedName, instructionSetInfo.InstructionSet);
}

_profileDataManager = profileDataManager;

_methodImportationErrorProvider = errorProvider;
Expand Down Expand Up @@ -213,28 +203,6 @@ private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeN
Logger.LogError($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis);
}
}

public override MethodIL GetMethodIL(MethodDesc method)
{
TypeDesc owningType = method.OwningType;
string intrinsicId = InstructionSetSupport.GetHardwareIntrinsicId(TypeSystemContext.Target.Architecture, owningType);
if (!string.IsNullOrEmpty(intrinsicId)
&& HardwareIntrinsicHelpers.IsIsSupportedMethod(method))
{
InstructionSet instructionSet = _instructionSetMap[intrinsicId];

// If this is an instruction set that is optimistically supported, but is not one of the
// intrinsics that are known to be always available, emit IL that checks the support level
// at runtime.
if (!InstructionSetSupport.IsInstructionSetSupported(instructionSet)
&& InstructionSetSupport.OptimisticFlags.HasInstructionSet(instructionSet))
{
return HardwareIntrinsicHelpers.EmitIsSupportedIL(method, _hardwareIntrinsicFlags, instructionSet);
}
}

return base.GetMethodIL(method);
}
}

[Flags]
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/tools/aot/ILCompiler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Internal.TypeSystem.Ecma;

using ILCompiler.Dataflow;
using ILCompiler.DependencyAnalysis;
using ILLink.Shared;

using Debug = System.Diagnostics.Debug;
Expand Down Expand Up @@ -143,6 +144,11 @@ public int Run()
if (typeSystemContext.InputFilePaths.Count == 0)
throw new CommandLineException("No input files specified");

ilProvider = new HardwareIntrinsicILProvider(
instructionSetSupport,
new ExternSymbolMappedField(typeSystemContext.GetWellKnownType(WellKnownType.Int32), "g_cpuFeatures"),
ilProvider);

SecurityMitigationOptions securityMitigationOptions = 0;
string guard = Get(_command.Guard);
if (StringComparer.OrdinalIgnoreCase.Equals(guard, "cf"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;

using BindingFlags = System.Reflection.BindingFlags;

Expand All @@ -14,6 +15,7 @@ internal class Program
private static int Main()
{
#if !MULTIMODULE_BUILD
TestHardwareIntrinsics.Run();
TestLdstr.Run();
TestException.Run();
TestThreadStaticNotInitialized.Run();
Expand Down Expand Up @@ -62,6 +64,39 @@ private static int Main()
}
}

class TestHardwareIntrinsics
{
class Simple1
{
public static bool IsSseSupported = Sse.IsSupported;
}

class Simple2
{
public static bool IsAvxVnniSupported = AvxVnni.IsSupported;
}

class Complex
{
public static bool IsPopcntSupported = Popcnt.IsSupported;
}

public static void Run()
{
Assert.IsPreinitialized(typeof(Simple1));
Assert.AreEqual(Sse.IsSupported, Simple1.IsSseSupported);

Assert.IsPreinitialized(typeof(Simple2));
Assert.AreEqual(AvxVnni.IsSupported, Simple2.IsAvxVnniSupported);

if (RuntimeInformation.ProcessArchitecture is Architecture.X86 or Architecture.X64)
Assert.IsLazyInitialized(typeof(Complex));
else
Assert.IsPreinitialized(typeof(Complex));
Assert.AreEqual(Popcnt.IsSupported, Complex.IsPopcntSupported);
}
}

class TestLdstr
{
static string s_mine;
Expand Down

0 comments on commit d1d6a6b

Please sign in to comment.