Skip to content

Commit

Permalink
Fixed retrieving kernel object from launchers with implicit stream.
Browse files Browse the repository at this point in the history
  • Loading branch information
MoFtZ committed Oct 20, 2022
1 parent c265515 commit 1f8baea
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
1 change: 1 addition & 0 deletions Src/ILGPU.Tests/Configurations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ DebugTests
DisassemblerTests
EnumValues
FixedBuffers
GetKernelTests
Indices
KernelEntryPoints
MemoryBufferOperations
Expand Down
80 changes: 80 additions & 0 deletions Src/ILGPU.Tests/GetKernelTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2022 ILGPU Project
// www.ilgpu.net
//
// File: GetKernelTests.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.Runtime;
using Xunit;
using Xunit.Abstractions;

namespace ILGPU.Tests
{
public abstract class GetKernelTests : TestBase
{
protected GetKernelTests(ITestOutputHelper output, TestContext testContext)
: base(output, testContext)
{ }

[Fact]
public void LoadAutoGroupedKernel()
{
var launcher =
Accelerator.LoadAutoGroupedKernel<Index1D, ArrayView<int>>(
(index, view) =>
{
view[index] = index;
});

var kernel = launcher.GetKernel();
Assert.NotNull(kernel);
}

[Fact]
public void LoadAutoGroupedStreamKernel()
{
var launcher =
Accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<int>>(
(index, view) =>
{
view[index] = index;
});

var kernel = launcher.GetKernel();
Assert.NotNull(kernel);
}

[Fact]
public void LoadKernel()
{
var launcher =
Accelerator.LoadKernel<Index1D, ArrayView<int>>(
(index, view) =>
{
view[index] = index;
});

var kernel = launcher.GetKernel();
Assert.NotNull(kernel);
}

[Fact]
public void LoadStreamKernel()
{
var launcher =
Accelerator.LoadStreamKernel<Index1D, ArrayView<int>>(
(index, view) =>
{
view[index] = index;
});

var kernel = launcher.GetKernel();
Assert.NotNull(kernel);
}
}
}
47 changes: 44 additions & 3 deletions Src/ILGPU/Runtime/Kernel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2017-2021 ILGPU Project
// Copyright (c) 2017-2022 ILGPU Project
// www.ilgpu.net
//
// File: Kernel.cs
Expand Down Expand Up @@ -408,8 +408,49 @@ public static class KernelUtil
public static bool TryGetKernel<TDelegate>(
this TDelegate kernelDelegate,
out Kernel kernel)
where TDelegate : Delegate =>
(kernel = kernelDelegate.Target as Kernel) != null;
where TDelegate : Delegate
{
// Try to resolve the kernel object from the delegate directly.
if (kernelDelegate.Target is Kernel targetKernel)
{
kernel = targetKernel;
return true;
}
else
{
// Kernel delegates that implicitly use the default accelerator stream
// are actually a lambda that calls an inner delegate. The kernel object
// needs to be extracted from this inner delegate using reflection.
var displayClass = kernelDelegate.Method.DeclaringType;

if (displayClass.IsDefined(typeof(CompilerGeneratedAttribute), false))
{
var capturedFields = displayClass.GetFields(
BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic);

foreach (var field in capturedFields)
{
if (typeof(Delegate).IsAssignableFrom(field.FieldType))
{
var fieldValue = field.GetValue(kernelDelegate.Target);
if (fieldValue is Delegate innerDelegate)
{
if (innerDelegate.Target is Kernel innerKernel)
{
kernel = innerKernel;
return true;
}
}
}
}
}

kernel = null;
return false;
}
}

/// <summary>
/// Resolves a kernel object from a previously created kernel delegate.
Expand Down

0 comments on commit 1f8baea

Please sign in to comment.