Skip to content

Commit 829ccce

Browse files
committed
Fixed invalid alignment of vector loads in PTX backend.
1 parent a7305a0 commit 829ccce

5 files changed

Lines changed: 91 additions & 37 deletions

File tree

Src/ILGPU/Backends/PTX/PTXBackend.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ protected override StringBuilder CreateKernelBuilder(
168168
? PointerAlignments.Create(
169169
backendContext.KernelMethod,
170170
DefaultGlobalMemoryAlignment)
171-
: PointerAlignments.Empty;
171+
: null;
172172

173173
data = new PTXCodeGenerator.GeneratorArgs(
174174
this,

Src/ILGPU/Backends/PTX/PTXCodeGenerator.Emitter.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -659,21 +659,27 @@ public void EmitComplexCommandWithOffsets<TEmitter>(
659659
/// to resolve the correct offset in bytes within a structure.
660660
/// </summary>
661661
/// <typeparam name="TEmitter">The emitter type.</typeparam>
662+
/// <param name="pointerValue">The pointer to get the alignment for.</param>
663+
/// <param name="safeAlignment">The safe minimum alignment in bytes.</param>
662664
/// <param name="command">The generic command to emit.</param>
663665
/// <param name="emitter">The current emitter.</param>
664666
/// <param name="register">The involved register.</param>
665-
/// <param name="alignment">The base alignment in bytes.</param>
666667
[MethodImpl(MethodImplOptions.AggressiveInlining)]
667668
public void EmitVectorizedCommand<TEmitter>(
669+
Value pointerValue,
670+
int safeAlignment,
668671
string command,
669672
in TEmitter emitter,
670-
Register register,
671-
int alignment)
673+
Register register)
672674
where TEmitter : IVectorizedCommandEmitter
673675
{
674-
if (register is CompoundRegister compoundRegister)
676+
if (PointerAlignments != null &&
677+
register is CompoundRegister compoundRegister)
675678
{
676679
// Check the provided alignment value to create vectorized instructions
680+
int alignment = PointerAlignments.GetAlignment(
681+
pointerValue,
682+
safeAlignment);
677683
var ranges = compoundRegister.Type.VectorizableFields;
678684
for (int i = 0, e = ranges.Count; i < e; ++i)
679685
{

Src/ILGPU/Backends/PTX/PTXCodeGenerator.Values.cs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -439,15 +439,12 @@ public void GenerateCode(Load load)
439439
var sourceType = load.Source.Type as PointerType;
440440
var targetRegister = Allocate(load);
441441

442-
// Query alignment information to emit vectorized instructions
443-
int alignment = PointerAlignments.GetAlignment(
444-
load.Source,
445-
sourceType.ElementType.Alignment);
446442
EmitVectorizedCommand(
443+
load.Source,
444+
sourceType.ElementType.Alignment,
447445
PTXInstructions.LoadOperation,
448446
new LoadEmitter(sourceType, address),
449-
targetRegister,
450-
alignment);
447+
targetRegister);
451448
}
452449

453450
/// <summary>
@@ -540,15 +537,12 @@ public void GenerateCode(Store store)
540537
var targetType = store.Target.Type as PointerType;
541538
var value = Load(store.Value);
542539

543-
// Query alignment information to emit vectorized instructions
544-
int baseAlignment = PointerAlignments.GetAlignment(
545-
store.Target,
546-
targetType.ElementType.Alignment);
547540
EmitVectorizedCommand(
541+
store.Target,
542+
targetType.ElementType.Alignment,
548543
PTXInstructions.StoreOperation,
549544
new StoreEmitter(targetType, address),
550-
value,
551-
baseAlignment);
545+
value);
552546
}
553547

554548
/// <summary cref="IBackendCodeGenerator.GenerateCode(LoadFieldAddress)"/>

Src/ILGPU/IR/Analyses/PointerAlignments.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,15 @@ public readonly int Merge(int first, int second) =>
8484
{
8585
LoadFieldAddress lfa =>
8686
AnalysisValue.Create(
87-
context[lfa.Source].Data +
88-
lfa.StructureType.GetOffset(lfa.FieldSpan.Access),
89-
lfa.Type),
87+
Math.Min(
88+
context[lfa.Source].Data,
89+
lfa.StructureType[lfa.FieldSpan.Access].Alignment),
90+
lfa.Type),
9091
LoadElementAddress lea =>
9192
AnalysisValue.Create(
92-
Math.Min(
93+
Math.Max(
9394
context[lea.Source].Data,
94-
(lea.Type as IAddressSpaceType).ElementType.Size),
95+
(lea.Type as IAddressSpaceType).ElementType.Alignment),
9596
lea.Type),
9697
_ => null,
9798
};

Src/ILGPU/IR/Types/StructureType.cs

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
using System.Diagnostics.CodeAnalysis;
1919
using System.Reflection;
2020
using System.Runtime.CompilerServices;
21-
using System.Security.Permissions;
2221
using System.Text;
2322

2423
namespace ILGPU.IR.Types
@@ -410,19 +409,23 @@ public readonly struct VectorizableFieldCollection
410409
/// </summary>
411410
public struct Entry
412411
{
412+
#region Instance
413+
413414
/// <summary>
414415
/// Constructs a new entry.
415416
/// </summary>
416-
internal Entry(TypeNode type, int index, int offset, int count = 1)
417+
internal Entry(
418+
TypeNode type,
419+
int index,
420+
int offset,
421+
int count = 1)
417422
{
418423
Type = type;
419424
Index = index;
420425
Count = count;
421426
Offset = offset;
422427
}
423428

424-
#region Instance
425-
426429
#endregion
427430

428431
#region Properties
@@ -440,17 +443,39 @@ internal Entry(TypeNode type, int index, int offset, int count = 1)
440443
/// <summary>
441444
/// Returns the number of fields.
442445
/// </summary>
443-
public int Count { get; private set; }
446+
public int Count { readonly get; private set; }
444447

445448
/// <summary>
446449
/// Returns the base offset in bytes from the beginning of the field.
447450
/// </summary>
448451
public int Offset { get; }
449452

453+
/// <summary>
454+
/// Returns the required alignment in bytes.
455+
/// </summary>
456+
public readonly int RequiredAlignment => Count * Type.Size;
457+
450458
#endregion
451459

452460
#region Methods
453461

462+
/// <summary>
463+
/// Splits the current entry into two parts.
464+
/// </summary>
465+
/// <param name="first">The first part.</param>
466+
/// <param name="second">The second part.</param>
467+
internal void Split(out Entry first, out Entry second)
468+
{
469+
Type.Assert(Count > 1);
470+
int firstCount = Count >> 1 + Count % 2;
471+
first = new Entry(Type, Index, Offset, firstCount);
472+
second = new Entry(
473+
Type,
474+
Index + firstCount,
475+
Offset + Type.Size * firstCount,
476+
Count - firstCount);
477+
}
478+
454479
/// <summary>
455480
/// Adds a field to this entry.
456481
/// </summary>
@@ -463,7 +488,22 @@ internal Entry(TypeNode type, int index, int offset, int count = 1)
463488
/// <param name="alignment">The underlying alignment in bytes.</param>
464489
/// <returns>True, if the range is properly aligned.</returns>
465490
public readonly bool IsAligned(int alignment) =>
466-
(alignment + Offset) % (Type.Size * Count) == 0;
491+
// Check for a proper alignment of the base address
492+
alignment % RequiredAlignment == 0;
493+
494+
/// <summary>
495+
/// Returns true if this entry can be properly aligned.
496+
/// </summary>
497+
/// <param name="parentType">The parent structure type.</param>
498+
internal readonly bool CanBeAligned(StructureType parentType)
499+
{
500+
int requiredAlignment = RequiredAlignment;
501+
return
502+
// Check for a relative alignment inside the structure
503+
Offset % requiredAlignment == 0 &&
504+
// Check for a relative alignment of odd structure accesses
505+
(Offset + parentType.Size) % requiredAlignment == 0;
506+
}
467507

468508
#endregion
469509
}
@@ -499,7 +539,7 @@ internal VectorizableFieldCollection(StructureType structureType)
499539
currentOffset + nextType.Size != nextOffset)
500540
{
501541
// Register the current vectorizable entry
502-
RegisterRange(current);
542+
RegisterRange(structureType, current);
503543
current = new Entry(
504544
nextType,
505545
i,
@@ -514,14 +554,17 @@ internal VectorizableFieldCollection(StructureType structureType)
514554
}
515555

516556
// Add the last entry
517-
RegisterRange(current);
557+
RegisterRange(structureType, current);
518558
}
519559

520560
/// <summary>
521561
/// Registers the given range entry.
522562
/// </summary>
563+
/// <param name="structureType">The parent structure type.</param>
523564
/// <param name="entry">The entry to register.</param>
524-
private void RegisterRange(in Entry entry)
565+
private void RegisterRange(
566+
StructureType structureType,
567+
in Entry entry)
525568
{
526569
int offset = entry.Offset;
527570
for (
@@ -531,12 +574,22 @@ private void RegisterRange(in Entry entry)
531574
{
532575
for (; index + stepSize <= entry.Count; index += stepSize)
533576
{
534-
ranges.Add(
535-
new Entry(
536-
entry.Type,
537-
index + entry.Index,
538-
offset,
539-
stepSize));
577+
var newEntry = new Entry(
578+
entry.Type,
579+
index + entry.Index,
580+
offset,
581+
stepSize);
582+
if (newEntry.Count > 1 && !newEntry.CanBeAligned(structureType))
583+
{
584+
newEntry.Split(out var first, out var second);
585+
RegisterRange(structureType, first);
586+
RegisterRange(structureType, second);
587+
}
588+
else
589+
{
590+
// The entry is properly aligned
591+
ranges.Add(newEntry);
592+
}
540593
offset += entry.Type.Size * stepSize;
541594
}
542595
}

0 commit comments

Comments
 (0)