yum-archive/TaSTT-Whisper

High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model

git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper

KonstantinSource codes8c4603c

master
7.6 KiB274 linesraw
1#include "stdafx.h"
2#include <intrin.h>
3#include "mulMatImpl.h"
4#include "mulMatUtils.hpp"
5using namespace CpuCompute;
6
7// We want to keep code size reasonable, that's why these panel reshaping methods are in the base class
8HRESULT MulMatBase::transposePanel( uint16_t* rdi, size_t i, size_t m2, size_t m3 ) const
9{
10	assert( stridesA[ 0 ] == 1 );
11
12	const size_t heightFloats = (size_t)panelHeightRegisters * 8;
13	i *= heightFloats;
14
15	const uint16_t* rsi = (const uint16_t*)pa;
16	rsi += m3 * stridesA[ 3 ];
17	rsi += m2 * stridesA[ 2 ];
18	rsi += i * stridesA[ 1 ];
19
20	const size_t resultStride = heightFloats;
21
22	if( i + heightFloats <= resultSize[ 0 ] )
23	{
24		// A complete panel
25		for( size_t i = 0; i < panelHeightRegisters; i++ )
26		{
27			transpose8( rdi, length, rsi, stridesA[ 1 ], resultStride );
28			// Advance by 8 floats in the output buffer
29			rdi += 8;
30			// Advance by 8 rows in the source matrix
31			rsi += 8 * stridesA[ 1 ];
32		}
33	}
34	else
35	{
36		// A partial panel, at the bottom of the first argument matrix
37		const size_t remainder = resultSize[ 0 ] - i;
38		assert( remainder > 0 && remainder < heightFloats );
39		zeroAlignedMemory( rdi, resultStride * length * sizeof( uint16_t ) );
40
41		const size_t completePanels = remainder / 8;
42		for( size_t i = 0; i < completePanels; i++ )
43		{
44			transpose8( rdi, length, rsi, stridesA[ 1 ], resultStride );
45			rdi += 8;
46			rsi += 8 * stridesA[ 1 ];
47		}
48		const size_t lastPanel = remainder % 8;
49		if( 0 != lastPanel )
50			transpose8Partial( rdi, length, lastPanel, rsi, stridesA[ 1 ], resultStride );
51	}
52	return S_OK;
53}
54
55inline const uint16_t* MulMatBase::getPanelA( size_t i, size_t m2, size_t m3 ) const
56{
57	const uint16_t* rsi = (const uint16_t*)pa;
58	rsi += m3 * stridesA[ 3 ];
59	rsi += m2 * stridesA[ 2 ];
60	rsi += i * stridesA[ 1 ];
61	return rsi;
62}
63
64HRESULT MulMatBase::copyPanelColumnMajor8( uint16_t* rdi, size_t i, size_t m2, size_t m3 ) const
65{
66	assert( stridesA[ 1 ] == 1 );
67	assert( panelHeightRegisters == 1 );
68
69	constexpr size_t heightFloats = 8;
70	i *= heightFloats;
71	const uint16_t* rsi = getPanelA( i, m2, m3 );
72
73	constexpr size_t resultStride = heightFloats;
74
75	if( i + heightFloats <= resultSize[ 0 ] )
76	{
77		// A complete panel, height = 8 elements
78		copyColumnMajor( rdi, length, rsi, stridesA[ 0 ], resultStride );
79	}
80	else
81	{
82		// A partial panel, at the bottom of the first argument matrix
83		const size_t remainder = resultSize[ 0 ] - i;
84		assert( remainder > 0 && remainder < heightFloats );
85		copyColumnMajorPartial( rdi, length, remainder, rsi, stridesA[ 0 ], resultStride );
86	}
87	return S_OK;
88}
89
90__forceinline __m128i load8Partial( const uint16_t* x, size_t len )
91{
92	assert( len > 0 && len < 8 );
93	__m128i ix = _mm_setzero_si128();
94	switch( len )
95	{
96	case 1: // load 2 bytes
97		ix = _mm_cvtsi32_si128( *x );
98		break;
99	case 2: // load 4 bytes
100		ix = _mm_cvtsi32_si128( *(const int*)x );
101		break;
102	case 3: // load 6 bytes
103		ix = _mm_cvtsi32_si128( *(const int*)x );
104		ix = _mm_insert_epi16( ix, x[ 2 ], 2 );
105		break;
106	case 4: // load 8 bytes
107		ix = _mm_cvtsi64_si128( *(const int64_t*)x );
108		break;
109	case 5: // load 10 bytes
110		ix = _mm_cvtsi64_si128( *(const int64_t*)x );
111		ix = _mm_insert_epi16( ix, x[ 4 ], 4 );
112		break;
113	case 6: // load 12 bytes
114		ix = _mm_cvtsi64_si128( *(const int64_t*)x );
115		ix = _mm_insert_epi32( ix, *(const int*)( x + 4 ), 2 );
116		break;
117	case 7: // load 14 bytes
118		ix = _mm_cvtsi64_si128( *(const int64_t*)x );
119		ix = _mm_insert_epi32( ix, *(const int*)( x + 4 ), 2 );
120		ix = _mm_insert_epi16( ix, x[ 6 ], 6 );
121		break;
122	}
123	return ix;
124}
125
126__forceinline __m256i load16Partial( const uint16_t* rsi, size_t len )
127{
128	assert( len > 0 && len < 16 );
129
130	if( len < 8 )
131	{
132		__m128i low = load8Partial( rsi, len );
133		return _mm256_setr_m128i( low, _mm_setzero_si128() );
134	}
135	else if( len > 8 )
136	{
137		__m128i low = load16( (const int*)rsi );
138		__m128i high = load8Partial( rsi + 8, len - 8 );
139		return _mm256_setr_m128i( low, high );
140	}
141	else
142	{
143		__m128i low = load16( (const int*)rsi );
144		return _mm256_setr_m128i( low, _mm_setzero_si128() );
145	}
146}
147
148HRESULT MulMatBase::copyPanelColumnMajor16( uint16_t* rdi, size_t i, size_t m2, size_t m3 ) const
149{
150	assert( stridesA[ 1 ] == 1 );
151	assert( panelHeightRegisters == 2 );
152
153	constexpr size_t heightFloats = 16;
154	i *= heightFloats;
155
156	const uint16_t* rsi = getPanelA( i, m2, m3 );
157	uint16_t* const rdiEnd = rdi + 16 * length;
158
159	if( i + heightFloats <= resultSize[ 0 ] )
160	{
161		// A complete panel, height = 16 elements
162		for( ; rdi < rdiEnd; rdi += 16, rsi += stridesA[ 0 ] )
163		{
164			__m256i v = _mm256_loadu_si256( ( const __m256i* )rsi );
165			_mm256_store_si256( ( __m256i* )rdi, v );
166		}
167	}
168	else
169	{
170		// A partial panel, at the bottom of the first argument matrix
171		const size_t remainder = resultSize[ 0 ] - i;
172		assert( remainder > 0 && remainder < heightFloats );
173
174		for( ; rdi < rdiEnd; rdi += 16, rsi += stridesA[ 0 ] )
175		{
176			__m256i v = load16Partial( rsi, remainder );
177			_mm256_store_si256( ( __m256i* )rdi, v );
178		}
179	}
180	return S_OK;
181}
182
183HRESULT MulMatBase::copyPanelColumnMajor32( uint16_t* rdi, size_t i, size_t m2, size_t m3 ) const
184{
185	assert( stridesA[ 1 ] == 1 );
186	assert( panelHeightRegisters == 4 );
187
188	constexpr size_t heightFloats = 32;
189	i *= heightFloats;
190
191	const uint16_t* rsi = getPanelA( i, m2, m3 );
192	uint16_t* const rdiEnd = rdi + 32 * length;
193
194	if( i + heightFloats <= resultSize[ 0 ] )
195	{
196		// A complete panel, height = 32 elements
197		for( ; rdi < rdiEnd; rdi += 32, rsi += stridesA[ 0 ] )
198		{
199			__m256i v = _mm256_loadu_si256( ( const __m256i* )rsi );
200			_mm256_store_si256( ( __m256i* )rdi, v );
201			v = _mm256_loadu_si256( ( const __m256i* )( rsi + 16 ) );
202			_mm256_store_si256( ( __m256i* )( rdi + 16 ), v );
203		}
204	}
205	else
206	{
207		// A partial panel, at the bottom of the first argument matrix
208		const size_t remainder = resultSize[ 0 ] - i;
209		assert( remainder > 0 && remainder < heightFloats );
210
211		// _mm256_setzero_si256 probably compiles into vpxor, that's AVX2, we don't want that here
212		const __m256 zero = _mm256_setzero_ps();
213
214		for( ; rdi < rdiEnd; rdi += 32, rsi += stridesA[ 0 ] )
215		{
216			if( remainder < 16 )
217			{
218				__m256i v = load16Partial( rsi, remainder );
219				_mm256_store_si256( ( __m256i* )rdi, v );
220				_mm256_store_ps( (float*)( rdi + 16 ), zero );
221			}
222			else if( remainder > 16 )
223			{
224				__m256i v = _mm256_loadu_si256( ( const __m256i* )rsi );
225				_mm256_store_si256( ( __m256i* )rdi, v );
226				v = load16Partial( rsi + 16, remainder - 16 );
227				_mm256_store_si256( ( __m256i* )( rdi + 16 ), v );
228			}
229			else
230			{
231				__m256i v = _mm256_loadu_si256( ( const __m256i* )rsi );
232				_mm256_store_si256( ( __m256i* )rdi, v );
233				_mm256_store_ps( (float*)( rdi + 16 ), zero );
234			}
235		}
236	}
237	return S_OK;
238}
239
240HRESULT MulMatBase::gatherPanel( uint16_t* rdi, size_t i, size_t m2, size_t m3 ) const
241{
242	// BTW, I never saw this method called.
243	const size_t heightFloats = (size_t)panelHeightRegisters * 8;
244	const size_t length = this->length;
245
246	zeroAlignedMemory( rdi, length * heightFloats * sizeof( uint16_t ) );
247
248	const size_t height = std::min( heightFloats, resultSize[ 0 ] - i );
249	const size_t strideElement = stridesA[ 0 ];
250	const size_t strideRow = stridesA[ 1 ];
251	const uint16_t* rsi = getPanelA( i * heightFloats, m2, m3 );
252
253	if( strideElement < strideRow )
254	{
255		for( size_t r = 0; r < height; r++, rsi += strideRow, rdi++ )
256		{
257			const uint16_t* sourceRow = rsi;
258			uint16_t* destRow = rdi;
259			for( size_t c = 0; c < length; c++, sourceRow += strideElement, destRow += heightFloats )
260				*destRow = *sourceRow;
261		}
262	}
263	else
264	{
265		for( size_t c = 0; c < length; c++, rsi += strideElement, rdi += heightFloats )
266		{
267			const uint16_t* sourceCol = rsi;
268			uint16_t* destCol = rdi;
269			for( size_t r = 0; r < height; r++, sourceCol += strideRow, destCol++ )
270				*destCol = *sourceCol;
271		}
272	}
273	return S_OK;
274}