Skip to content

Commit

Permalink
Fixed alignment of Int128 type. (#1176)
Browse files Browse the repository at this point in the history
  • Loading branch information
MoFtZ authored Apr 9, 2024
1 parent 0ea975f commit 870f2b6
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 21 deletions.
74 changes: 74 additions & 0 deletions Src/ILGPU.Tests/KernelEntryPoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -690,5 +690,79 @@ public void UnsupportedEntryPointParameter<T>(T value)
Execute(kernel.Method, extent, buffer.View, value));
Assert.IsType<NotSupportedException>(e.InnerException);
}

#if NET7_0_OR_GREATER
internal static void PreParamAlignmentKernel(
Index1D index,
Int128 constant,
ArrayView1D<Int128, Stride1D.Dense> output)
{
output[index] = index.X + constant;
}

[Theory]
[InlineData(33)]
[InlineData(1025)]
[KernelMethod(nameof(PreParamAlignmentKernel))]
public void PreParamAlignment(int length)
{
Int128 c = 42;
using var buffer = Accelerator.Allocate1D<Int128>(length);
Execute(buffer.Length, c, buffer.View);

var expected = Enumerable.Range(0, length).Select(x => x + c).ToArray();
Verify(buffer.View, expected);
}

internal static void PostParamAlignmentKernel(
Index1D index,
ArrayView1D<Int128, Stride1D.Dense> output,
Int128 constant)
{
output[index] = index.X + constant;
}

[Theory]
[InlineData(33)]
[InlineData(1025)]
[KernelMethod(nameof(PostParamAlignmentKernel))]
public void PostParamAlignment(int length)
{
Int128 c = 42;
using var buffer = Accelerator.Allocate1D<Int128>(length);
Execute(buffer.Length, buffer.View, c);

var expected = Enumerable.Range(0, length).Select(x => x + c).ToArray();
Verify(buffer.View, expected);
}

public struct MyAlignedStruct
{
public byte X;
public Int128 Y;
}

internal static void AlignedStructParamAlignmentKernel(
Index1D index,
ArrayView1D<Int128, Stride1D.Dense> output,
MyAlignedStruct constant)
{
output[index] = index.X + constant.Y;
}

[Theory]
[InlineData(33)]
[InlineData(1025)]
[KernelMethod(nameof(AlignedStructParamAlignmentKernel))]
public void AlignedStructParamAlignment(int length)
{
MyAlignedStruct c = new MyAlignedStruct { Y = 42 };
using var buffer = Accelerator.Allocate1D<Int128>(length);
Execute(buffer.Length, buffer.View, c);

var expected = Enumerable.Range(0, length).Select(x => x + c.Y).ToArray();
Verify(buffer.View, expected);
}
#endif
}
}
68 changes: 50 additions & 18 deletions Src/ILGPU/IR/Types/IRTypeContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2023 ILGPU Project
// Copyright (c) 2018-2024 ILGPU Project
// www.ilgpu.net
//
// File: IRTypeContext.cs
Expand Down Expand Up @@ -410,30 +410,44 @@ private TypeNode CreateType_Sync(Type type, MemoryAddressSpace addressSpace)
}
else
{
// Must be a structure type
if (!type.IsValueType)
{
throw new NotSupportedException(
string.Format(
ErrorMessages.NotSupportedType,
type));
}

var typeInfo = GetTypeInfo(type);
var builder = new StructureType.Builder(
this,
typeInfo.NumFlattendedFields,
typeInfo.Size);
foreach (var field in typeInfo.Fields)
builder.Add(CreateType_Sync(field.FieldType, addressSpace));

PrepareStructureType(type, addressSpace, out var builder);
return Map(
type,
addressSpace,
UnifyType(builder.Seal()));
}
}

/// <summary>
/// Creates a new structure type based on a type from the .Net world.
/// The builder is returned so that further customization can be performed.
/// </summary>
/// <param name="type">The source type.</param>
/// <param name="addressSpace">The address space for pointer types.</param>
/// <param name="builder">Filled in with the structure builder.</param>
private void PrepareStructureType(
Type type,
MemoryAddressSpace addressSpace,
out StructureType.Builder builder)
{
// Must be a structure type
if (!type.IsValueType)
{
throw new NotSupportedException(
string.Format(
ErrorMessages.NotSupportedType,
type));
}

var typeInfo = GetTypeInfo(type);
builder = new StructureType.Builder(
this,
typeInfo.NumFlattendedFields,
typeInfo.Size);
foreach (var field in typeInfo.Fields)
builder.Add(CreateType_Sync(field.FieldType, addressSpace));
}

/// <summary>
/// Specializes the address space of the given <see cref="AddressSpaceType"/>.
/// </summary>
Expand Down Expand Up @@ -513,6 +527,9 @@ private void PopulateTypeMapping()
{
typeMapping.Add((typeof(void), space), VoidType);
typeMapping.Add((typeof(string), space), StringType);
#if NET7_0_OR_GREATER
typeMapping.Add((typeof(Int128), space), CreateInt128Type(space));
#endif

typeMapping.Add((typeof(Array), space), RootType);

Expand All @@ -531,6 +548,21 @@ private void PopulateTypeMapping()
}
}

#if NET7_0_OR_GREATER
/// <summary>
/// Creates the structure type for <see cref="Int128"/>.
/// This is considered an intrinsic in the .Net world, and is internally aligned
/// to 16 bytes.
/// </summary>
private TypeNode CreateInt128Type(MemoryAddressSpace addressSpace)
{
// Force 16 byte alignment.
PrepareStructureType(typeof(Int128), addressSpace, out var builder);
builder.Alignment = 16;
return UnifyType(builder.Seal());
}
#endif

/// <summary>
/// Clears all internal caches.
/// </summary>
Expand Down
8 changes: 5 additions & 3 deletions Src/ILGPU/IR/Types/StructureType.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------------------
// ILGPU
// Copyright (c) 2018-2023 ILGPU Project
// Copyright (c) 2018-2024 ILGPU Project
// www.ilgpu.net
//
// File: StructureType.cs
Expand Down Expand Up @@ -93,7 +93,7 @@ internal Builder(
/// <summary>
/// The current alignment for the underlying type.
/// </summary>
public int Alignment { get; private set; }
public int Alignment { get; internal set; }

/// <summary>
/// The current size in bytes.
Expand Down Expand Up @@ -840,6 +840,7 @@ public StructureType ConvertFieldTypes<TTypeContext, TTypeConverter>(
builder.Add(convertedType);
changed |= convertedType != type;
}
builder.Alignment = Alignment;

// Ensure that we did not lose any fields
this.Assert(builder.Count >= NumFields);
Expand Down Expand Up @@ -975,7 +976,8 @@ protected override Type GetManagedType<TTypeProvider>(
public override bool Equals(object? obj)
{
if (!(obj is StructureType structureType) ||
structureType.NumFields != NumFields)
structureType.NumFields != NumFields ||
structureType.Alignment != Alignment)
{
return false;
}
Expand Down

0 comments on commit 870f2b6

Please sign in to comment.