Skip to content

Commit

Permalink
Added sample project for Static Abstract Interface Members. (#970)
Browse files Browse the repository at this point in the history
  • Loading branch information
MoFtZ committed Mar 16, 2023
1 parent b33fbf2 commit 55b08a4
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Samples/ILGPU.Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorSampleApp", "BlazorSa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemoryBufferStrides", "MemoryBufferStrides\MemoryBufferStrides.csproj", "{2EF99A5B-9AAE-44A8-BB41-923DF66A7EAB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StaticAbstractInterfaceMembers", "StaticAbstractInterfaceMembers\StaticAbstractInterfaceMembers.csproj", "{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -351,6 +353,10 @@ Global
{2EF99A5B-9AAE-44A8-BB41-923DF66A7EAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2EF99A5B-9AAE-44A8-BB41-923DF66A7EAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2EF99A5B-9AAE-44A8-BB41-923DF66A7EAB}.Release|Any CPU.Build.0 = Release|Any CPU
{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -414,6 +420,7 @@ Global
{029C809E-4EBF-4437-A4B2-BA7E14A9C023} = {C1D99632-ED4A-4B08-A14D-4C8DB375934F}
{1A909DA2-15AE-466F-8BBE-C3F676C39812} = {30F390DB-B823-40A2-A881-382B9EF36C07}
{2EF99A5B-9AAE-44A8-BB41-923DF66A7EAB} = {C1D99632-ED4A-4B08-A14D-4C8DB375934F}
{28FD07DE-7B7D-46C3-9EE1-5D50C0E4F126} = {C1D99632-ED4A-4B08-A14D-4C8DB375934F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {30E502BD-3826-417F-888F-1CE19CF5C6DA}
Expand Down
159 changes: 159 additions & 0 deletions Samples/StaticAbstractInterfaceMembers/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// ---------------------------------------------------------------------------------------
// ILGPU Samples
// Copyright (c) 2023 ILGPU Project
// www.ilgpu.net
//
// File: Program.cs
//
// This file is part of ILGPU and is distributed under the University of Illinois Open
// Source License. See LICENSE.txt for details.
// ---------------------------------------------------------------------------------------

using ILGPU;
using ILGPU.Runtime;
using System;
using System.Linq;

namespace StaticAbstractInterfaceMembers
{
class Program
{
// .NET 7 introduced Static Abstract Interface Members. These can either be used
// by themselves, or combined with Generic Math, to provide the ability to write
// generic kernels with different implementations for some functionality.
//
// Before .NET 7, a more restricted option is to use a struct that implements
// the generic interface.
//
#if NET7_0_OR_GREATER
public interface ICalculatorOperation<T>
where T : System.Numerics.INumber<T>
{
static abstract T Calculate(T left, T right);
}

// Interface can be implemented by a 'class' or 'struct'.
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Performance",
"CA1812:Avoid uninstantiated internal classes",
Justification = "Using static method in ILGPU kernel")]
public class AdditionOp : ICalculatorOperation<int>
{
public static int Calculate(int left, int right) => left + right;
}

// Interface can be implemented by a 'class' or 'struct'.
public struct MultiplyOp : ICalculatorOperation<float>
{
public static float Calculate(float left, float right) => left * right;
}

public static void CalculatorKernel<T, TOp>(
Index1D index,
ArrayView1D<T, Stride1D.Dense> input,
ArrayView1D<T, Stride1D.Dense> output)
where T : unmanaged, System.Numerics.INumber<T>
where TOp : ICalculatorOperation<T>
{
// Calls the static abstract method on the class or struct.
output[index] = TOp.Calculate(input[index], input[index]);
}

#else

public interface ICalculatorOperation<T>
where T : unmanaged
{
T Calculate(T left, T right);
}

// Interface must be implemented by a 'struct'.
public struct AdditionOp : ICalculatorOperation<int>
{
public int Calculate(int left, int right) => left + right;
}

// Interface must be implemented by a 'struct'.
public struct MultiplyOp : ICalculatorOperation<float>
{
public float Calculate(float left, float right) => left * right;
}

public static void CalculatorKernel<T, TOp>(
Index1D index,
ArrayView1D<T, Stride1D.Dense> input,
ArrayView1D<T, Stride1D.Dense> output)
where T : unmanaged
where TOp : struct, ICalculatorOperation<T>
{
// Creates a new instance of the struct, and calls the method.
output[index] = default(TOp).Calculate(input[index], input[index]);
}

#endif

public static void UsingAbstractFunction<T, TOp>(Accelerator accelerator)
#if NET7_0_OR_GREATER
where T : unmanaged, System.Numerics.INumber<T>
where TOp : ICalculatorOperation<T>
#else
where T : unmanaged
where TOp : struct, ICalculatorOperation<T>
#endif
{
var values =
Enumerable.Range(0, 16)
#if NET7_0_OR_GREATER
.Select(x => T.CreateChecked(x))
#else
.Select(x => (T)Convert.ChangeType(
x,
typeof(T),
System.Globalization.CultureInfo.InvariantCulture))
#endif
.ToArray();
using var inputBuffer = accelerator.Allocate1D(values);
using var outputBuffer = accelerator.Allocate1D(values);

outputBuffer.MemSetToZero();

var kernel = accelerator.LoadAutoGroupedStreamKernel<
Index1D,
ArrayView1D<T, Stride1D.Dense>,
ArrayView1D<T, Stride1D.Dense>>(
CalculatorKernel<T, TOp>);

kernel(
(int)inputBuffer.Length,
inputBuffer.View,
outputBuffer.View);

accelerator.Synchronize();

var result = outputBuffer.GetAsArray1D();
for (var i = 0; i < result.Length; i++)
Console.WriteLine($"[{i}] = {result[i]}");
Console.WriteLine();
}

/// <summary>
/// Demonstrates static abstract members in interfaces.
/// </summary>
static void Main()
{
// Create main context
using var context = Context.CreateDefault();

// For each available device...
foreach (var device in context)
{
// Create accelerator for the given device
using var accelerator = device.CreateAccelerator(context);
Console.WriteLine($"Performing operations on {accelerator}");

UsingAbstractFunction<int, AdditionOp>(accelerator);
UsingAbstractFunction<float, MultiplyOp>(accelerator);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibrarySamplesTargetFrameworks)</TargetFrameworks>
<OutputType>Exe</OutputType>
<LangVersion>11.0</LangVersion>
</PropertyGroup>

<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Src\ILGPU\ILGPU.csproj" />
</ItemGroup>
</Project>

0 comments on commit 55b08a4

Please sign in to comment.