Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support static abstract interface members #930

Merged
merged 1 commit into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Src/ILGPU.Tests/Configurations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ DisassemblerTests
EnumValues
FixedBuffers
GetKernelTests
GenericMath
Indices
KernelEntryPoints
MemoryBufferOperations
Expand All @@ -14,6 +13,7 @@ ProfilingMarkers
SharedMemory
SizeOfValues
SpecializedKernels
StaticAbstractInterfaceMembers
StructureValues
ValueTuples
InteropTests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
{ }

Expand All @@ -34,6 +36,8 @@ public static T GeZeroIfBigger<T>(T value, T max) where T : INumber<T>
return value;
}

#region Generic math

internal static void GenericMathKernel<T>(
Index1D index,
ArrayView1D<T, Stride1D.Dense> input,
Expand Down Expand Up @@ -94,6 +98,56 @@ public void GenericMathDoubleTest()
TestGenericMathKernel(input, expected, MaxValue);
}

#endregion

internal static void IncrementingKernel<T>(
Index1D index,
ArrayView1D<int, Stride1D.Dense> input,
ArrayView1D<int, Stride1D.Dense> output)
where T : IStaticAbstract
{
output[index] = T.Inc(input[index]);
}

private void TestIncrementingKernel<T>(int[] inputValues, int[] expected)
where T : IStaticAbstract
{
using var input = Accelerator.Allocate1D<int>(inputValues);
using var output = Accelerator.Allocate1D<int>(Length);

using var start = Accelerator.DefaultStream.AddProfilingMarker();
Accelerator.LaunchAutoGrouped<
Index1D,
ArrayView1D<int, Stride1D.Dense>,
ArrayView1D<int, Stride1D.Dense>>(
IncrementingKernel<T>,
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<Incrementer>(input, expected);
}
#endif
}
}
18 changes: 17 additions & 1 deletion Src/ILGPU/Frontend/CodeGenerator/Calls.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2021 ILGPU Project
// Copyright (c) 2018-2023 ILGPU Project
// www.ilgpu.net
//
// File: Calls.cs
Expand Down Expand Up @@ -66,6 +66,22 @@ private void CreateCall(
}
}

/// <summary>
/// Realizes a call instruction.
/// </summary>
/// <param name="instruction">The instruction to realize.</param>
private void MakeCall(ILInstruction instruction)
MoFtZ marked this conversation as resolved.
Show resolved Hide resolved
{
var method = instruction.GetArgumentAs<MethodBase>();
if (instruction.HasFlags(ILInstructionFlags.Constrained)
&& method is MethodInfo methodInfo)
{
var constrainedType = instruction.FlagsContext.Argument as Type;
method = ResolveVirtualCallTarget(methodInfo, constrainedType);
}
MakeCall(method);
}

/// <summary>
/// Realizes a call instruction.
/// </summary>
Expand Down
5 changes: 2 additions & 3 deletions Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2022 ILGPU Project
// Copyright (c) 2018-2023 ILGPU Project
// www.ilgpu.net
//
// File: CodeGenerator.cs
Expand Down Expand Up @@ -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];
Expand Down
4 changes: 2 additions & 2 deletions Src/ILGPU/Frontend/CodeGenerator/Driver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2021 ILGPU Project
// Copyright (c) 2018-2023 ILGPU Project
// www.ilgpu.net
//
// File: Driver.cs
Expand Down Expand Up @@ -129,7 +129,7 @@ private bool TryGenerateCode(ILInstruction instruction)
MakeReturn();
return true;
case ILInstructionType.Call:
MakeCall(instruction.GetArgumentAs<MethodBase>());
MakeCall(instruction);
return true;
case ILInstructionType.Callvirt:
MakeVirtualCall(instruction);
Expand Down
60 changes: 3 additions & 57 deletions Src/ILGPU/Frontend/Disassembler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2022 ILGPU Project
// Copyright (c) 2018-2023 ILGPU Project
// www.ilgpu.net
//
// File: Disassembler.cs
Expand All @@ -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;
Expand All @@ -28,60 +27,7 @@ namespace ILGPU.Frontend
/// <remarks>Members of this class are not thread safe.</remarks>
public sealed partial class Disassembler : ILocation
{
#region Static

/// <summary>
/// Indicates whether the .NET runtime has support for Static Abstract methods
/// in Interfaces.
/// </summary>
[SuppressMessage("Performance", "CA1802:Use literals where appropriate")]
private static readonly bool UsingStaticAbstractMethodsInInterfaces =
#if NET7_0_OR_GREATER
RuntimeFeature.IsSupported(RuntimeFeature.VirtualStaticsInInterfaces);
#else
false;
#endif

/// <summary>
/// Extracts the method body for the given method.
/// </summary>
/// <param name="method">The method.</param>
/// <returns>The method body.</returns>
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

/// <summary>
/// Represents the native pointer type that is used during the
Expand Down Expand Up @@ -152,7 +98,7 @@ public Disassembler(
? MethodBase.GetGenericArguments()
: Array.Empty<Type>();
TypeGenericArguments = MethodBase.DeclaringType.GetGenericArguments();
MethodBody = ExtractMethodBody(MethodBase);
MethodBody = MethodBase.GetMethodBody();
if (MethodBody == null)
{
throw new NotSupportedException(string.Format(
Expand Down