1818using System . Diagnostics . CodeAnalysis ;
1919using System . Reflection ;
2020using System . Runtime . CompilerServices ;
21- using System . Security . Permissions ;
2221using System . Text ;
2322
2423namespace 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