11// Copyright (c) Six Labors.
22// Licensed under the Six Labors Split License.
33
4- using System . Buffers . Binary ;
5- using System . Numerics ;
6- using System . Runtime . CompilerServices ;
7- using System . Runtime . InteropServices ;
8- using static SixLabors . ImageSharp . SimdUtils ;
9-
104// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
115// and ROTR (Rotate Right) emitting efficient CPU instructions:
126// https://github.com/dotnet/coreclr/pull/1830
@@ -19,190 +13,24 @@ namespace SixLabors.ImageSharp;
1913internal interface IComponentShuffle
2014{
2115 /// <summary>
22- /// Shuffles then slices 8-bit integers within 128-bit lanes in <paramref name="source"/>
23- /// using the control and store the results in <paramref name="dest"/>.
16+ /// Shuffles then slices 8-bit integers in <paramref name="source"/>
17+ /// using a byte control and store the results in <paramref name="destination"/>.
18+ /// If successful, this method will reduce the length of <paramref name="source"/> length
19+ /// by the shuffle amount.
2420 /// </summary>
2521 /// <param name="source">The source span of bytes.</param>
26- /// <param name="dest ">The destination span of bytes.</param>
27- void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest ) ;
22+ /// <param name="destination ">The destination span of bytes.</param>
23+ void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > destination ) ;
2824
2925 /// <summary>
30- /// Shuffle 8-bit integers within 128-bit lanes in <paramref name="source"/>
31- /// using the control and store the results in <paramref name="dest "/>.
26+ /// Shuffle 8-bit integers in <paramref name="source"/>
27+ /// using the control and store the results in <paramref name="destination "/>.
3228 /// </summary>
3329 /// <param name="source">The source span of bytes.</param>
34- /// <param name="dest ">The destination span of bytes.</param>
30+ /// <param name="destination ">The destination span of bytes.</param>
3531 /// <remarks>
36- /// Implementation can assume that source.Length is less or equal than dest .Length.
32+ /// Implementation can assume that source.Length is less or equal than destination .Length.
3733 /// Loops should iterate using source.Length.
3834 /// </remarks>
39- void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest ) ;
40- }
41-
42- /// <inheritdoc/>
43- internal interface IShuffle4 : IComponentShuffle
44- {
45- }
46-
47- internal readonly struct DefaultShuffle4 : IShuffle4
48- {
49- public DefaultShuffle4 ( byte control )
50- => this . Control = control ;
51-
52- public byte Control { get ; }
53-
54- [ MethodImpl ( InliningOptions . ShortMethod ) ]
55- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
56- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , this . Control ) ;
57-
58- [ MethodImpl ( InliningOptions . ShortMethod ) ]
59- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
60- {
61- ref byte sBase = ref MemoryMarshal . GetReference ( source ) ;
62- ref byte dBase = ref MemoryMarshal . GetReference ( dest ) ;
63-
64- Shuffle . InverseMMShuffle ( this . Control , out uint p3 , out uint p2 , out uint p1 , out uint p0 ) ;
65-
66- for ( nuint i = 0 ; i < ( uint ) source . Length ; i += 4 )
67- {
68- Unsafe . Add ( ref dBase , i + 0 ) = Unsafe. Add ( ref sBase , p0 + i ) ;
69- Unsafe . Add ( ref dBase , i + 1 ) = Unsafe. Add ( ref sBase , p1 + i ) ;
70- Unsafe . Add ( ref dBase , i + 2 ) = Unsafe. Add ( ref sBase , p2 + i ) ;
71- Unsafe . Add ( ref dBase , i + 3 ) = Unsafe. Add ( ref sBase , p3 + i ) ;
72- }
73- }
74- }
75-
76- internal readonly struct WXYZShuffle4 : IShuffle4
77- {
78- [ MethodImpl ( InliningOptions . ShortMethod ) ]
79- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
80- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , Shuffle . MMShuffle2103 ) ;
81-
82- [ MethodImpl ( InliningOptions . ShortMethod ) ]
83- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
84- {
85- ref uint sBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( source ) ) ;
86- ref uint dBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( dest ) ) ;
87- uint n = ( uint ) source . Length / 4 ;
88-
89- for ( nuint i = 0 ; i < n ; i ++ )
90- {
91- uint packed = Unsafe . Add ( ref sBase , i ) ;
92-
93- // packed = [W Z Y X]
94- // ROTL(8, packed) = [Z Y X W]
95- Unsafe . Add ( ref dBase , i ) = ( packed << 8 ) | ( packed >> 24 ) ;
96- }
97- }
98- }
99-
100- internal readonly struct WZYXShuffle4 : IShuffle4
101- {
102- [ MethodImpl ( InliningOptions . ShortMethod ) ]
103- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
104- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , Shuffle . MMShuffle0123 ) ;
105-
106- [ MethodImpl ( InliningOptions . ShortMethod ) ]
107- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
108- {
109- ref uint sBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( source ) ) ;
110- ref uint dBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( dest ) ) ;
111- uint n = ( uint ) source . Length / 4 ;
112-
113- for ( nuint i = 0 ; i < n ; i ++ )
114- {
115- uint packed = Unsafe . Add ( ref sBase , i ) ;
116-
117- // packed = [W Z Y X]
118- // REVERSE(packedArgb) = [X Y Z W]
119- Unsafe . Add ( ref dBase , i ) = BinaryPrimitives. ReverseEndianness ( packed ) ;
120- }
121- }
122- }
123-
124- internal readonly struct YZWXShuffle4 : IShuffle4
125- {
126- [ MethodImpl ( InliningOptions . ShortMethod ) ]
127- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
128- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , Shuffle . MMShuffle0321 ) ;
129-
130- [ MethodImpl ( InliningOptions . ShortMethod ) ]
131- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
132- {
133- ref uint sBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( source ) ) ;
134- ref uint dBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( dest ) ) ;
135- uint n = ( uint ) source . Length / 4 ;
136-
137- for ( nuint i = 0 ; i < n ; i ++ )
138- {
139- uint packed = Unsafe . Add ( ref sBase , i ) ;
140-
141- // packed = [W Z Y X]
142- // ROTR(8, packedArgb) = [Y Z W X]
143- Unsafe . Add ( ref dBase , i ) = BitOperations. RotateRight ( packed , 8 ) ;
144- }
145- }
146- }
147-
148- internal readonly struct ZYXWShuffle4 : IShuffle4
149- {
150- [ MethodImpl ( InliningOptions . ShortMethod ) ]
151- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
152- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , Shuffle . MMShuffle3012 ) ;
153-
154- [ MethodImpl ( InliningOptions . ShortMethod ) ]
155- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
156- {
157- ref uint sBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( source ) ) ;
158- ref uint dBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( dest ) ) ;
159- uint n = ( uint ) source . Length / 4 ;
160-
161- for ( nuint i = 0 ; i < n ; i ++ )
162- {
163- uint packed = Unsafe . Add ( ref sBase , i ) ;
164-
165- // packed = [W Z Y X]
166- // tmp1 = [W 0 Y 0]
167- // tmp2 = [0 Z 0 X]
168- // tmp3=ROTL(16, tmp2) = [0 X 0 Z]
169- // tmp1 + tmp3 = [W X Y Z]
170- uint tmp1 = packed & 0xFF00FF00 ;
171- uint tmp2 = packed & 0x00FF00FF ;
172- uint tmp3 = BitOperations . RotateLeft ( tmp2 , 16 ) ;
173-
174- Unsafe . Add ( ref dBase , i ) = tmp1 + tmp3 ;
175- }
176- }
177- }
178-
179- internal readonly struct XWZYShuffle4 : IShuffle4
180- {
181- [ MethodImpl ( InliningOptions . ShortMethod ) ]
182- public void ShuffleReduce ( ref ReadOnlySpan < byte > source , ref Span < byte > dest )
183- => HwIntrinsics . Shuffle4Reduce ( ref source , ref dest , Shuffle . MMShuffle1230 ) ;
184-
185- [ MethodImpl ( InliningOptions . ShortMethod ) ]
186- public void RunFallbackShuffle ( ReadOnlySpan < byte > source , Span < byte > dest )
187- {
188- ref uint sBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( source ) ) ;
189- ref uint dBase = ref Unsafe . As < byte , uint > ( ref MemoryMarshal . GetReference ( dest ) ) ;
190- uint n = ( uint ) source . Length / 4 ;
191-
192- for ( nuint i = 0 ; i < n ; i ++ )
193- {
194- uint packed = Unsafe . Add ( ref sBase , i ) ;
195-
196- // packed = [W Z Y X]
197- // tmp1 = [0 Z 0 X]
198- // tmp2 = [W 0 Y 0]
199- // tmp3=ROTL(16, tmp2) = [Y 0 W 0]
200- // tmp1 + tmp3 = [Y Z W X]
201- uint tmp1 = packed & 0x00FF00FF ;
202- uint tmp2 = packed & 0xFF00FF00 ;
203- uint tmp3 = BitOperations . RotateLeft ( tmp2 , 16 ) ;
204-
205- Unsafe . Add ( ref dBase , i ) = tmp1 + tmp3 ;
206- }
207- }
35+ void Shuffle ( ReadOnlySpan < byte > source , Span < byte > destination ) ;
20836}
0 commit comments