diff --git a/Src/ILGPU.Tests/Configurations.txt b/Src/ILGPU.Tests/Configurations.txt index 547d176e1..9c187a867 100644 --- a/Src/ILGPU.Tests/Configurations.txt +++ b/Src/ILGPU.Tests/Configurations.txt @@ -5,7 +5,6 @@ DisassemblerTests EnumValues FixedBuffers GetKernelTests -GenericMath Indices KernelEntryPoints MemoryBufferOperations @@ -14,6 +13,7 @@ ProfilingMarkers SharedMemory SizeOfValues SpecializedKernels +StaticAbstractInterfaceMembers StructureValues ValueTuples InteropTests diff --git a/Src/ILGPU.Tests/GenericMath.cs b/Src/ILGPU.Tests/StaticAbstractInterfaceMembers.cs similarity index 60% rename from Src/ILGPU.Tests/GenericMath.cs rename to Src/ILGPU.Tests/StaticAbstractInterfaceMembers.cs index b67c34597..2310a42fd 100644 --- a/Src/ILGPU.Tests/GenericMath.cs +++ b/Src/ILGPU.Tests/StaticAbstractInterfaceMembers.cs @@ -3,7 +3,7 @@ // Copyright (c) 2022-2023 ILGPU Project // www.ilgpu.net // -// File: GenericMath.cs +// File: StaticAbstractInterfaceMembers.cs // // This file is part of ILGPU and is distributed under the University of Illinois Open // Source License. See LICENSE.txt for details. @@ -17,9 +17,11 @@ namespace ILGPU.Tests { - public abstract class GenericMath : TestBase + public abstract class StaticAbstractInterfaceMembers : TestBase { - protected GenericMath(ITestOutputHelper output, TestContext testContext) + protected StaticAbstractInterfaceMembers( + ITestOutputHelper output, + TestContext testContext) : base(output, testContext) { } @@ -34,6 +36,8 @@ public static T GeZeroIfBigger(T value, T max) where T : INumber return value; } + #region Generic math + internal static void GenericMathKernel( Index1D index, ArrayView1D input, @@ -94,6 +98,56 @@ public void GenericMathDoubleTest() TestGenericMathKernel(input, expected, MaxValue); } + #endregion + + internal static void IncrementingKernel( + Index1D index, + ArrayView1D input, + ArrayView1D output) + where T : IStaticAbstract + { + output[index] = T.Inc(input[index]); + } + + private void TestIncrementingKernel(int[] inputValues, int[] expected) + where T : IStaticAbstract + { + using var input = Accelerator.Allocate1D(inputValues); + using var output = Accelerator.Allocate1D(Length); + + using var start = Accelerator.DefaultStream.AddProfilingMarker(); + Accelerator.LaunchAutoGrouped< + Index1D, + ArrayView1D, + ArrayView1D>( + IncrementingKernel, + Accelerator.DefaultStream, + (int)input.Length, + input.View, + output.View); + + Verify(output.View, expected); + } + + public interface IStaticAbstract + { + static abstract int Inc(int x); + } + + public class Incrementer: IStaticAbstract + { + public static int Inc(int x) => x + 1; + } + + [Fact] + public void StaticInterfaceTest() + { + int[] input = Enumerable.Range(0, Length).ToArray(); + + int[] expected = input.Select(Incrementer.Inc).ToArray(); + + TestIncrementingKernel(input, expected); + } #endif } } diff --git a/Src/ILGPU/Frontend/CodeGenerator/Calls.cs b/Src/ILGPU/Frontend/CodeGenerator/Calls.cs index f5edfc2e9..60acf6e5d 100644 --- a/Src/ILGPU/Frontend/CodeGenerator/Calls.cs +++ b/Src/ILGPU/Frontend/CodeGenerator/Calls.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU -// Copyright (c) 2018-2021 ILGPU Project +// Copyright (c) 2018-2023 ILGPU Project // www.ilgpu.net // // File: Calls.cs @@ -66,6 +66,22 @@ private void CreateCall( } } + /// + /// Realizes a call instruction. + /// + /// The instruction to realize. + private void MakeCall(ILInstruction instruction) + { + var method = instruction.GetArgumentAs(); + if (instruction.HasFlags(ILInstructionFlags.Constrained) + && method is MethodInfo methodInfo) + { + var constrainedType = instruction.FlagsContext.Argument as Type; + method = ResolveVirtualCallTarget(methodInfo, constrainedType); + } + MakeCall(method); + } + /// /// Realizes a call instruction. /// diff --git a/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs b/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs index 943458860..d1b70fcf1 100644 --- a/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs +++ b/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU -// Copyright (c) 2018-2022 ILGPU Project +// Copyright (c) 2018-2023 ILGPU Project // www.ilgpu.net // // File: CodeGenerator.cs @@ -142,8 +142,7 @@ private void SetupVariables() } // Initialize locals - var methodBody = Disassembler.ExtractMethodBody(Method); - var localVariables = methodBody.LocalVariables; + var localVariables = Method.GetMethodBody().LocalVariables; for (int i = 0, e = localVariables.Count; i < e; ++i) { var variable = localVariables[i]; diff --git a/Src/ILGPU/Frontend/CodeGenerator/Driver.cs b/Src/ILGPU/Frontend/CodeGenerator/Driver.cs index f39e780b1..38a564cb3 100644 --- a/Src/ILGPU/Frontend/CodeGenerator/Driver.cs +++ b/Src/ILGPU/Frontend/CodeGenerator/Driver.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU -// Copyright (c) 2018-2021 ILGPU Project +// Copyright (c) 2018-2023 ILGPU Project // www.ilgpu.net // // File: Driver.cs @@ -129,7 +129,7 @@ private bool TryGenerateCode(ILInstruction instruction) MakeReturn(); return true; case ILInstructionType.Call: - MakeCall(instruction.GetArgumentAs()); + MakeCall(instruction); return true; case ILInstructionType.Callvirt: MakeVirtualCall(instruction); diff --git a/Src/ILGPU/Frontend/Disassembler.cs b/Src/ILGPU/Frontend/Disassembler.cs index b9bf47786..f71592774 100644 --- a/Src/ILGPU/Frontend/Disassembler.cs +++ b/Src/ILGPU/Frontend/Disassembler.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU -// Copyright (c) 2018-2022 ILGPU Project +// Copyright (c) 2018-2023 ILGPU Project // www.ilgpu.net // // File: Disassembler.cs @@ -15,7 +15,6 @@ using ILGPU.Util; using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; @@ -28,60 +27,7 @@ namespace ILGPU.Frontend /// Members of this class are not thread safe. public sealed partial class Disassembler : ILocation { - #region Static - - /// - /// Indicates whether the .NET runtime has support for Static Abstract methods - /// in Interfaces. - /// - [SuppressMessage("Performance", "CA1802:Use literals where appropriate")] - private static readonly bool UsingStaticAbstractMethodsInInterfaces = -#if NET7_0_OR_GREATER - RuntimeFeature.IsSupported(RuntimeFeature.VirtualStaticsInInterfaces); -#else - false; -#endif - - /// - /// Extracts the method body for the given method. - /// - /// The method. - /// The method body. - public static MethodBody ExtractMethodBody(MethodBase method) - { - var methodBody = method.GetMethodBody(); - if (methodBody == null && - UsingStaticAbstractMethodsInInterfaces && - method.DeclaringType.IsInterface && - method.IsStatic && - method.IsAbstract) - { - // Support for Static Abstract methods in Interfaces was introduced in - // C# 11, in particular, adding support for Generic Math. The interface - // itself does not contain the method implementation itself. Instead, we - // need to find the concrete type that implements the interface, and find - // the matching method. - var concreteType = method.DeclaringType.GetGenericArguments()[0]; - var interfaceMap = concreteType.GetInterfaceMap(method.DeclaringType); - - for (int i = 0; i < interfaceMap.InterfaceMethods.Length; i++) - { - if (interfaceMap.InterfaceMethods[i].Name.Equals( - method.Name, - StringComparison.OrdinalIgnoreCase)) - { - methodBody = interfaceMap.TargetMethods[i].GetMethodBody(); - break; - } - } - } - - return methodBody; - } - -#endregion - -#region Constants + #region Constants /// /// Represents the native pointer type that is used during the @@ -152,7 +98,7 @@ public Disassembler( ? MethodBase.GetGenericArguments() : Array.Empty(); TypeGenericArguments = MethodBase.DeclaringType.GetGenericArguments(); - MethodBody = ExtractMethodBody(MethodBase); + MethodBody = MethodBase.GetMethodBody(); if (MethodBody == null) { throw new NotSupportedException(string.Format(