1
1
// Copyright (c) Six Labors.
2
2
// Licensed under the Six Labors Split License.
3
3
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
-
10
4
// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
11
5
// and ROTR (Rotate Right) emitting efficient CPU instructions:
12
6
// https://github.com/dotnet/coreclr/pull/1830
@@ -19,190 +13,24 @@ namespace SixLabors.ImageSharp;
19
13
internal interface IComponentShuffle
20
14
{
21
15
/// <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.
24
20
/// </summary>
25
21
/// <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 ) ;
28
24
29
25
/// <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 "/>.
32
28
/// </summary>
33
29
/// <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>
35
31
/// <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.
37
33
/// Loops should iterate using source.Length.
38
34
/// </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 ) ;
208
36
}
0 commit comments