ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
4 июля
1527709
klen (01.07.2025 23:56, просмотров: 207)
в связи с тем что в мои загребущие лапки едет NUCLEO-N657X0-Q... очень захотелось испытать этот ихний helium 

кто не в курсе - у ST не так давно появилась свежая серия микроконтроллеров серии stm32n6

https://www.st.com/en/microcontrollers-microprocessors/stm32n6-series.html

она содержит cortex-m55 который в свою очередь имеет связку даблового fpu и векторного расширения MVE ( другое название Helium )


доки на него



arm-hel…ing_for_helium_102095_0101_02_en.pdf

arm-helium-technology-mve.pdf


если коротко то отличия Гелия от Неона



из интересного видно что кроме прочего векторизация расширена в Гелии на целочисленные операции на целочисленных регистрах.

судя по всему если захочется векторная арифметика с фиксированной запятой - можно использовать как целые регистры так и плавающие

должно быть быстрее чем Неон


понятно что на асме или интринсиках мы вытянем все возможности из Гелия, но как всегда хоцца шоб компиллер сделла за нас ленивых работу - в GCC и LLVM есть такая фигня - auto-vectorization. при ее втыкании он пытается распреллелить дерево операций и если это получилось использовать для этого инструкции из векторного набора

https://gcc.gnu.org/projects/tree-ssa/vectorization.html



вот че получилось


исходник

#include <stdint.h>
#include <stddef.h>
void FooInt32(const int* __restrict__ a, const int* __restrict__ b, const int* __restrict__ c, const int* __restrict__ d, int* e, const size_t s) { for ( size_t i = 0 ; i < s ; i++ ) { e[i] = a[i ]*b[i ] - c[i ]*d[i ] ; } } void FooFloat32(const float* __restrict__ a, const float* __restrict__ b, const float* __restrict__ c, const float* __restrict__ d, float* e, const size_t s) { for ( size_t i = 0 ; i < s ; i++ ) { e[i] = a[i ]*b[i ] - c[i ]*d[i ] ; } }


функции нак написаны чтоб была явная парралеизация трассы вычисления


arm-kgp-eabi-gcc -g0 -c a.cc -Ofast -g0 -mcpu=cortex-m55 -mthumb -mfloat-abi=hard



00000000 <_Z8FooInt32PKiS0_S0_S0_Pij>:
   0:	e92d 47f0 	stmdb	sp!, {r4, r5, r6, r7, r8, r9, sl, lr}
   4:	e9dd 4608 	ldrd	r4, r6, [sp, #32]
   8:	2e00      	cmp	r6, #0
   a:	d06a      	beq.n	e2 <_Z8FooInt32PKiS0_S0_S0_Pij+0xe2>
   c:	4699      	mov	r9, r3
   e:	1e73      	subs	r3, r6, #1
  10:	2b02      	cmp	r3, #2
  12:	4607      	mov	r7, r0
  14:	4688      	mov	r8, r1
  16:	4615      	mov	r5, r2
  18:	d965      	bls.n	e6 <_Z8FooInt32PKiS0_S0_S0_Pij+0xe6>
  1a:	ea4f 0a96 	mov.w	sl, r6, lsr #2
  1e:	ea4f 1e0a 	mov.w	lr, sl, lsl #4
  22:	f1ae 0e10 	sub.w	lr, lr, #16
  26:	ea4f 1e1e 	mov.w	lr, lr, lsr #4
  2a:	f10e 0e01 	add.w	lr, lr, #1
  2e:	f04e e001 	dls	lr, lr
  32:	f04f 0c00 	mov.w	ip, #0
  36:	eb09 030c 	add.w	r3, r9, ip
  3a:	eb07 000c 	add.w	r0, r7, ip
  3e:	eb08 010c 	add.w	r1, r8, ip
  42:	eb05 020c 	add.w	r2, r5, ip
  46:	ed93 3f00 	vldrw.u32	q1, [r3, #0]
  4a:	ed90 7f00 	vldrw.u32	q3, [r0, #0]
  4e:	ed91 1f00 	vldrw.u32	q0, [r1, #0]
  52:	ed92 5f00 	vldrw.u32	q2, [r2, #0]
  56:	ef26 6950 	vmul.i32	q3, q3, q0
  5a:	ef24 4952 	vmul.i32	q2, q2, q1
  5e:	ff26 6844 	vsub.i32	q3, q3, q2
  62:	eb04 030c 	add.w	r3, r4, ip
  66:	ed83 7f00 	vstrw.32	q3, [r3, #0]
  6a:	f10c 0c10 	add.w	ip, ip, #16
  6e:	f00f c01f 	le	lr, 36 <_Z8FooInt32PKiS0_S0_S0_Pij+0x36>
  72:	ebb6 0f8a 	cmp.w	r6, sl, lsl #2
  76:	ea4f 008a 	mov.w	r0, sl, lsl #2
  7a:	d032      	beq.n	e2 <_Z8FooInt32PKiS0_S0_S0_Pij+0xe2>
  7c:	f858 2020 	ldr.w	r2, [r8, r0, lsl #2]
  80:	f857 3020 	ldr.w	r3, [r7, r0, lsl #2]
  84:	f859 1020 	ldr.w	r1, [r9, r0, lsl #2]
  88:	fb02 f303 	mul.w	r3, r2, r3
  8c:	f855 2020 	ldr.w	r2, [r5, r0, lsl #2]
  90:	fb01 3312 	mls	r3, r1, r2, r3
  94:	1c42      	adds	r2, r0, #1
  96:	4296      	cmp	r6, r2
  98:	f844 3020 	str.w	r3, [r4, r0, lsl #2]
  9c:	ea4f 0380 	mov.w	r3, r0, lsl #2
  a0:	d91f      	bls.n	e2 <_Z8FooInt32PKiS0_S0_S0_Pij+0xe2>
  a2:	f103 0c04 	add.w	ip, r3, #4
  a6:	f858 100c 	ldr.w	r1, [r8, ip]
  aa:	f857 200c 	ldr.w	r2, [r7, ip]
  ae:	f100 0e02 	add.w	lr, r0, #2
  b2:	fb01 f202 	mul.w	r2, r1, r2
  b6:	f859 000c 	ldr.w	r0, [r9, ip]
  ba:	f855 100c 	ldr.w	r1, [r5, ip]
  be:	4576      	cmp	r6, lr
  c0:	fb00 2211 	mls	r2, r0, r1, r2
  c4:	f844 200c 	str.w	r2, [r4, ip]
  c8:	d90b      	bls.n	e2 <_Z8FooInt32PKiS0_S0_S0_Pij+0xe2>
  ca:	3308      	adds	r3, #8
  cc:	58f8      	ldr	r0, [r7, r3]
  ce:	f858 2003 	ldr.w	r2, [r8, r3]
  d2:	f859 1003 	ldr.w	r1, [r9, r3]
  d6:	fb00 f202 	mul.w	r2, r0, r2
  da:	58e8      	ldr	r0, [r5, r3]
  dc:	fb00 2211 	mls	r2, r0, r1, r2
  e0:	50e2      	str	r2, [r4, r3]
  e2:	e8bd 87f0 	ldmia.w	sp!, {r4, r5, r6, r7, r8, r9, sl, pc}
  e6:	2000      	movs	r0, #0
  e8:	e7c8      	b.n	7c <_Z8FooInt32PKiS0_S0_S0_Pij+0x7c>
  ea:	bf00      	nop

000000ec <_Z10FooFloat32PKfS0_S0_S0_Pfj>:
  ec:	e92d 47f0 	stmdb	sp!, {r4, r5, r6, r7, r8, r9, sl, lr}
  f0:	e9dd 4608 	ldrd	r4, r6, [sp, #32]
  f4:	2e00      	cmp	r6, #0
  f6:	f000 8083 	beq.w	200 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x114>
  fa:	4699      	mov	r9, r3
  fc:	1e73      	subs	r3, r6, #1
  fe:	2b02      	cmp	r3, #2
 100:	4605      	mov	r5, r0
 102:	460f      	mov	r7, r1
 104:	4690      	mov	r8, r2
 106:	d97d      	bls.n	204 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x118>
 108:	ea4f 0a96 	mov.w	sl, r6, lsr #2
 10c:	ea4f 1e0a 	mov.w	lr, sl, lsl #4
 110:	f1ae 0e10 	sub.w	lr, lr, #16
 114:	ea4f 1e1e 	mov.w	lr, lr, lsr #4
 118:	f10e 0e01 	add.w	lr, lr, #1
 11c:	f04e e001 	dls	lr, lr
 120:	f04f 0c00 	mov.w	ip, #0
 124:	eb09 030c 	add.w	r3, r9, ip
 128:	eb05 000c 	add.w	r0, r5, ip
 12c:	eb07 010c 	add.w	r1, r7, ip
 130:	eb08 020c 	add.w	r2, r8, ip
 134:	ed93 3f00 	vldrw.u32	q1, [r3, #0]
 138:	ed90 7f00 	vldrw.u32	q3, [r0, #0]
 13c:	ed91 1f00 	vldrw.u32	q0, [r1, #0]
 140:	ed92 5f00 	vldrw.u32	q2, [r2, #0]
 144:	ff06 6d50 	vmul.f32	q3, q3, q0
 148:	ff04 4d52 	vmul.f32	q2, q2, q1
 14c:	ef26 6d44 	vsub.f32	q3, q3, q2
 150:	eb04 030c 	add.w	r3, r4, ip
 154:	ed83 7f00 	vstrw.32	q3, [r3, #0]
 158:	f10c 0c10 	add.w	ip, ip, #16
 15c:	f00f c01f 	le	lr, 124 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x38>
 160:	ebb6 0f8a 	cmp.w	r6, sl, lsl #2
 164:	ea4f 038a 	mov.w	r3, sl, lsl #2
 168:	d04a      	beq.n	200 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x114>
 16a:	eb08 0283 	add.w	r2, r8, r3, lsl #2
 16e:	ed92 6a00 	vldr	s12, [r2]
 172:	eb09 0283 	add.w	r2, r9, r3, lsl #2
 176:	edd2 7a00 	vldr	s15, [r2]
 17a:	eb05 0283 	add.w	r2, r5, r3, lsl #2
 17e:	edd2 6a00 	vldr	s13, [r2]
 182:	eb07 0283 	add.w	r2, r7, r3, lsl #2
 186:	ed92 7a00 	vldr	s14, [r2]
 18a:	ee67 7ac6 	vnmul.f32	s15, s15, s12
 18e:	eee6 7a87 	vfma.f32	s15, s13, s14
 192:	1c5a      	adds	r2, r3, #1
 194:	eb04 0083 	add.w	r0, r4, r3, lsl #2
 198:	4296      	cmp	r6, r2
 19a:	edc0 7a00 	vstr	s15, [r0]
 19e:	ea4f 0183 	mov.w	r1, r3, lsl #2
 1a2:	d92d      	bls.n	200 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x114>
 1a4:	1d0a      	adds	r2, r1, #4
 1a6:	eb08 0002 	add.w	r0, r8, r2
 1aa:	ed90 6a00 	vldr	s12, [r0]
 1ae:	eb09 0002 	add.w	r0, r9, r2
 1b2:	edd0 7a00 	vldr	s15, [r0]
 1b6:	18a8      	adds	r0, r5, r2
 1b8:	edd0 6a00 	vldr	s13, [r0]
 1bc:	18b8      	adds	r0, r7, r2
 1be:	ed90 7a00 	vldr	s14, [r0]
 1c2:	ee67 7ac6 	vnmul.f32	s15, s15, s12
 1c6:	eee6 7a87 	vfma.f32	s15, s13, s14
 1ca:	3302      	adds	r3, #2
 1cc:	4422      	add	r2, r4
 1ce:	429e      	cmp	r6, r3
 1d0:	edc2 7a00 	vstr	s15, [r2]
 1d4:	d914      	bls.n	200 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x114>
 1d6:	f101 0308 	add.w	r3, r1, #8
 1da:	4499      	add	r9, r3
 1dc:	4498      	add	r8, r3
 1de:	ed99 6a00 	vldr	s12, [r9]
 1e2:	edd8 7a00 	vldr	s15, [r8]
 1e6:	441f      	add	r7, r3
 1e8:	441d      	add	r5, r3
 1ea:	edd7 6a00 	vldr	s13, [r7]
 1ee:	ed95 7a00 	vldr	s14, [r5]
 1f2:	ee67 7ac6 	vnmul.f32	s15, s15, s12
 1f6:	eee6 7a87 	vfma.f32	s15, s13, s14
 1fa:	441c      	add	r4, r3
 1fc:	edc4 7a00 	vstr	s15, [r4]
 200:	e8bd 87f0 	ldmia.w	sp!, {r4, r5, r6, r7, r8, r9, sl, pc}
 204:	2300      	movs	r3, #0
 206:	e7b0      	b.n	16a <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x7e>

выше жирнентким выделеныинструкции Гелия и выдно что он трактует регистровый файл FPU как набор 128 битных регистров

если отключить авто-векторизацию то компиллер сгенерить код под FP сопроцессор


arm-kgp-eabi-gcc -g0 -c a.cc -Os -g0 -mcpu=cortex-m55 -mthumb -mfloat-abi=hard


00000000 <_Z8FooInt32PKiS0_S0_S0_Pij>:
   0:	b5f0      	push	{r4, r5, r6, r7, lr}
   2:	9d06      	ldr	r5, [sp, #24]
   4:	2400      	movs	r4, #0
   6:	f105 0e01 	add.w	lr, r5, #1
   a:	f04e e001 	dls	lr, lr
   e:	f1be 0e01 	subs.w	lr, lr, #1
  12:	d100      	bne.n	16 <_Z8FooInt32PKiS0_S0_S0_Pij+0x16>
  14:	bdf0      	pop	{r4, r5, r6, r7, pc}
  16:	f851 7024 	ldr.w	r7, [r1, r4, lsl #2]
  1a:	f850 5024 	ldr.w	r5, [r0, r4, lsl #2]
  1e:	f853 6024 	ldr.w	r6, [r3, r4, lsl #2]
  22:	437d      	muls	r5, r7
  24:	f852 7024 	ldr.w	r7, [r2, r4, lsl #2]
  28:	fb06 5517 	mls	r5, r6, r7, r5
  2c:	9e05      	ldr	r6, [sp, #20]
  2e:	f846 5024 	str.w	r5, [r6, r4, lsl #2]
  32:	3401      	adds	r4, #1
  34:	e7eb      	b.n	e <_Z8FooInt32PKiS0_S0_S0_Pij+0xe>

00000036 <_Z10FooFloat32PKfS0_S0_S0_Pfj>:
  36:	b530      	push	{r4, r5, lr}
  38:	e9dd 5403 	ldrd	r5, r4, [sp, #12]
  3c:	f024 4440 	bic.w	r4, r4, #3221225472	@ 0xc0000000
  40:	f104 0e01 	add.w	lr, r4, #1
  44:	f04e e001 	dls	lr, lr
  48:	f1be 0e01 	subs.w	lr, lr, #1
  4c:	d100      	bne.n	50 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x1a>
  4e:	bd30      	pop	{r4, r5, pc}
  50:	ecb2 6a01 	vldmia	r2!, {s12}
  54:	ecf3 7a01 	vldmia	r3!, {s15}
  58:	ecf0 6a01 	vldmia	r0!, {s13}
  5c:	ecb1 7a01 	vldmia	r1!, {s14}
  60:	ee67 7ac6 	vnmul.f32	s15, s15, s12
  64:	eee6 7a87 	vfma.f32	s15, s13, s14
  68:	ece5 7a01 	vstmia	r5!, {s15}
  6c:	e7ec      	b.n	48 <_Z10FooFloat32PKfS0_S0_S0_Pfj+0x12>

ну что ж... будем посмотреть как быстро ускорится FFT (в Гелии реализованы инструкции с комплексными числами), матричная арифметика и прочие собачьи радости.