Перейти к содержанию
    

О производительности memcpy

Надо будет проверить влияние этого на производительность.

Проверил интереса для. Должен сказать, что результаты вышли довольно любопытные, поэтому решил изложить их здесь.

 

В ходе эксперимента измерялась скорость копирования 256 блоков по одному мегабайту с различными смещениями источника и приемника данных. В качестве тестовой платформы использовался процессор EP9312 (ARM920T, FCLK = 200MHz, BCLK = 100MHz).

Первое число в квадратных скобках - смещение приемника, второе - источника, скорость приводится в мегабайтах в секунду:

copy[0][0]: 60.674
copy[1][0]: 45.506
copy[2][0]: 45.506
copy[3][0]: 45.506

copy[0][1]: 46.397
copy[1][1]: 55.246
copy[2][1]: 45.506
copy[3][1]: 45.506

copy[0][2]: 46.397
copy[1][2]: 46.397
copy[2][2]: 55.245
copy[3][2]: 45.506

copy[0][3]: 46.397
copy[1][3]: 46.397
copy[2][3]: 46.397
copy[3][3]: 55.245

Примечательны два обстоятельства:

1. Относительно небольшое против ожидаемого снижение скорости при работе с неодинаковыми смещениями у источника и приемника

2. Заметное падение скорости в условиях, казалось бы близких к идеальным (n, n; при n > 0).

 

Объяснение первому эффекту находится достаточно просто: 60 МБайт/с - это ограничение, накладываемое производительностью контроллера памяти. И если снизить частоту ядра, оставив частоту шины на том же уровне (FCLK = BCLK = 100MHz), то разница в результатах получается более значительной:

copy[0][0]: 60.672
copy[1][0]: 32.233
copy[2][0]: 32.233
copy[3][0]: 32.233

copy[0][1]: 32.233
copy[1][1]: 53.933
copy[2][1]: 32.233
copy[3][1]: 32.233
...

 

Второй эффект куда любопытнее. Доподлинно установить его происхождение не удалось. Можно только определенно сказать, что он не связан напрямую с работой кэша и буфера записи. Наиболее логичным представляется предположение, что смещение данных на слово ломает где-то burst-передачи, создавая тем самым некоторый оверхед. Скорее всего это особенность данного конкретного процессора и его контроллера памяти.

 

Зависимость скорости копирования от смещения данных, число в квадратных скобках - смещение в 32-битных словах:

copy[0w]: 60.674102
copy[1w]: 55.245381
copy[2w]: 55.226639
copy[3w]: 52.582269
copy[4w]: 60.672306
copy[5w]: 55.246603
copy[6w]: 55.211088
copy[7w]: 52.584118
copy[8w]: 60.674150
...

 

И, наконец, последняя табличка. Она показывает скорость копирования при расположении источника и приемника данных в разных банках SDRAM.

copy[0w]: 91.010796
copy[1w]: 79.629958
copy[2w]: 79.629988
copy[3w]: 73.539810
copy[4w]: 91.006777
copy[5w]: 79.630088
copy[6w]: 79.630112
copy[7w]: 73.539468
copy[8w]: 91.011220
...

 

 

Если резюмировать, то для эффективного копирования надо:

1. Выравнивать данные, причем иногда бывает мало и границы слова. Логичным представляется выравнивание по границе строки кэша.

2. По возможности располагать источник и приемник в разных банках SDRAM. Это позволит контроллеру памяти дольше держать банки открытыми (т.е. сэкономить на precharge).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут важнее каким компилером это делалось и какая шина была к SDRAM.

 

С другой стороны в драйверах где скорость особенно важна практически нет свободы выбора как будут размещены приходящие в драйвер данные.

Зато есть свобода выбора компилятора ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут важнее каким компилером это делалось и какая шина была к SDRAM.

Я бы сказал что не от компилятора, а от конкретной реализации memcpy() - она обычно на ассемблере пишется, компилятор никак не результат повлиять не может.

 

aaarrr

Вы не могли бы добавить архивчик с исходником использованной в Ваших тестах memcpy()? Для полноты картины :)

Про разные банки - эффект известный, Ваш тест очень хорошо его отобразил. Только пользоваться этим эффектом трудно, у тех контроллеров что мне попадались, биты адреса банка замешивались в середину физического адреса. И получалось что в адресном пространстве подряд шли страницы из разных банков, да еще они могли на разных платах быть разного размера - в зависимости от того какие чипы запаяли. В среднем (когда не задумываться о банках) это наверное эффективней, тем более в DDR2 банков уже может быть 8. Но при этом сознательно "разбанковать" данные становится трудновато.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я бы сказал что не от компилятора, а от конкретной реализации memcpy() - она обычно на ассемблере пишется, компилятор никак не результат повлиять не может.

 

Почему вы решили что все пишут на GCC?

Ни в IAR, ни в Keil, ни в GHS, ни в RealView исходники memcpy недоступны.

Никто бы не стал тестировать memcpy если б были исходники этой функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ни в IAR, ни в Keil, ни в GHS, ни в RealView исходники memcpy недоступны.

MS - доступны я ими когда-то пользовался, ибо в IAR 4x был мрак с memcpy(), но IAR - для 4x и 5.x день и ночь по результатам.

Keil - не знаю что там, но под drystone :) он когда-то славно подточен был.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему вы решили что все пишут на GCC?

Ни в IAR,

Надо признать, резон в замечании есть. Тут дело не столько в GCC, сколько в том, что memcpy() лично для меня функция важная и тщательно изученная не для одной архитектуры. Вот я и решил что все ее код "знают в лицо". Был неправ, что сказать . BTW, для IAR Full версии исходники доступны, и это они зря - там грустно :(

 

Никто бы не стал тестировать memcpy если б были исходники этой функции.

Исходники (ессно, в нормальном варианте) там бывают довольно любопытные - иногда я много нового узнаю :). ИМХО, тестировать memcpy() следует потому что на современных системах производительность зависит не только (далеко не только) от того что написано в исходнике этой функции. Лично я всегда при помощи тестов memcpy() (своей имплементации RTL) тюнингую настройки контроллера DRAM, арбитра шины и прочие подобные мелочи.

 

 

ибо в IAR 4x был мрак с memcpy(), но IAR - для 4x и 5.x день и ночь по результатам.

Э-э-э-э, то есть 5-ый еще хуже чем 4-ый? Да куда ж там дальше-то. Я последний раз IAR-овские исходники смотрел в 4.30 - правда мрак.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

IAR Full версии исходники доступны, и это они зря - там грустно :(

Э,то что Вам показалось исходниками, это не они, это какая-то заглушка. Исходников нет и в полной.

Э-э-э-э, то есть 5-ый еще хуже чем 4-ый? Да куда ж там дальше-то.

Вообще-то я хотел сказать, что совсем наоборот, и вроде так и сказал?

Вот, то, что использовал вместо штатного memcpy() в 4x IAR:

//---------------------------------------------------------------------------
// Fast memcpy() & memove() For IAR ARM ANSI C/C++ Compiler
//---------------------------------------------------------------------------

	NAME memcpy

	RSEG CSTACK:DATA:NOROOT(2)

	MULTWEAK ??memcpy??rT
	MULTWEAK ??memmove??rT
	PUBLIC memcpy
	PUBLIC memmove

memcpy			  SYMBOL "memcpy"
??memcpy??rT		SYMBOL "??rT", memcpy

memmove			 SYMBOL "memmove"
??memmove??rT	   SYMBOL "??rT", memmove


	RSEG CODE:CODE:NOROOT(2)
	THUMB
??memcpy??rT:
	BX	   PC
	Nop
	REQUIRE memcpy


	RSEG CODE:CODE:NOROOT(2)
	ARM

#ifndef configUSE_MEMCPY8W			  
			#define WORDS8_TRANSFER  0
#else 
	#if configUSE_MEMCPY8W == 1 
			#define WORDS8_TRANSFER  1
	#else
			#define WORDS8_TRANSFER  0
	#endif
#endif

//---------------------------------------------------------------------------
// void *(memcpy)(void *p1, const void *p2, size_t n)
// Copy char p2[n] to p1[n]
//---------------------------------------------------------------------------
memcpy:
	teq	  r2,#0				  // Is p1 == 0 ?
	bxeq	 lr					 // If p1 == 0, return

	stmdb	sp!,{lr}			   // Push return address
	mov	  r12,r0				 // Copy pointer p1
	cmp	  r2,#8				  // Is buffer long or short?
	ble	  byteserial			 // Jump if n <= 8

	sub	  r3,r0,r1			   // Compare pointers p1, p2
	tst	  r3,#3				  // Strings aligned same?
	bne	  byteserial			 // Jump if buffers not aligned


// Both strings are similarly aligned WRT word boundaries.
// At least a portion of the data can be copied an entire
// word at a time, which is faster than copying bytes.
wordserial:
	ands	 r3,r0,#3			   // Check byte alignment
	beq	  wordaligned			// Jump if p1, p2 word-aligned

	rsb	  r3,r3,#4			   // m = no. of odd initial bytes
	sub	  r2,r2,r3			   // n = n - m


// If the two buffers do not begin on word boundaries, begin
// by copying the odd bytes that precede the first full word.
preloop:
	ldrb	 lr,[r1],#1			 // Read byte from source
	subs	 r3,r3,#1			   // --m (decrement loop count)
	strb	 lr,[r12],#1			// Write byte to destination
	bne	  preloop				// Loop if more bytes to move


wordaligned:
#if WORDS8_TRANSFER == 1
	movs	 r3,r2,asr #5		   // Any chunks of 8 words?
	beq	  octsdone			   // Jump if no 8-word chunks

	and	  r2,r2,#0x1F			// Subtract chunks from n
	stmdb	sp!,{r4-r10}		   // Save registers on stack


// The strings are long enough that we can transfer at least
// some portion of the data in 8-word chunks.
octloop:
	ldmia	r1!,{r4-r10,lr}		// Load 8 words from source
	subs	 r3,r3,#1			   // More 8-word chunks to move?
	stmia	r12!,{r4-r10,lr}	   // Write 8 words to destination
	bne	  octloop				// Loop if more chunks

	ldmia	sp!,{r4-r10}		   // Restore registers from stack

octsdone:
#endif
	movs	 r3,r2,asr #2		   // Any more whole words to move?
	beq	  wordsdone			  // Jump if no more whole words


// Copy as much of the remaining data as possible one word at
// a time.
wordloop2:
	ldr	  lr,[r1],#4			 // Read next word from source
	subs	 r3,r3,#1			   // Decrement word count
	str	  lr,[r12],#4			// Write next word to destination
	bne	  wordloop2			  // Loop while more words to move

wordsdone:
	ands	 r2,r2,#3			   // Any last bytes to transfer?
	beq	  theend				 // Return if already done


// The two strings do not end on word boundaries.
// Copy the remaining data one byte at a time.
byteserial:
	ldrb	 lr,[r1],#1			 // Read byte from source
	subs	 r2,r2,#1			   // --n (decrement loop count)
	strb	 lr,[r12],#1			// Write byte to destination
	bne	  byteserial			 // Loop if more bytes to move

theend:
	ldmia	sp!,{lr}			   // Return
	bx	   lr

//---------------------------------------------------------------------------
	RSEG CODE:CODE:NOROOT(2)
	THUMB
??memmove??rT:
	BX	   PC
	Nop
	REQUIRE memmove


	RSEG CODE:CODE:NOROOT(2)
	ARM

//---------------------------------------------------------------------------
// Safely copy c bytes from source s to destination d.
// void *memmove(void *d, const void *s, unsigned c);
//---------------------------------------------------------------------------
memmove:
	cmp	  r0,r1		  // Is d > s ?
	bls	  memcpy		 // Jump to memcpy if d <= s

// Need to copy backwards, starting at tail ends of source and
// destination arrays.  Copy a word or a byte at a time?
	orr	  r3,r1,r0	   // tmp = s | d
	orr	  r3,r3,r2	   // tmp = s | d | c
	ands	 r3,r3,#3	   // Is tmp even multiple of 4?

	add	  r1,r1,r2	   // s + c (end of source buffer)
	add	  r2,r2,r0	   // d + c (end of dest'n buffer)
	beq	  move1		  // Jump if tmp is multiple of 4
	b		move2

// Because the source and destination arrays are not aligned to even
// word boundaries in memory, transfer only a byte at a time.
move3:
	ldrb	 r3,[r1,#-1]!   // Load next byte from source
	strb	 r3,[r2,#-1]!   // Store next byte to dest'n
move2:
	teq	  r0,r2		  // More bytes to move?
	bne	  move3		  // Jump if more bytes
	bx	   lr			 // All done

// Because count c is an even multiple of 4 and the source
// and destination arrays begin on even word boundaries, move
// an entire word at a time from source to destination.
move4:
	ldr	  r3,[r1,#-4]!   // Load next word from source
	str	  r3,[r2,#-4]!   // Store next word to dest'n
move1:
	teq	  r0,r2		  // More words to move?
	bne	  move4		  // Jump if more words

	bx	   lr			 // All done

	END

Есть еще один сишный memcpy(). Интересно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Э,то что Вам показалось исходниками, это не они, это какая-то заглушка. Исходников нет и в полной.

Да вроде специально глянул (в 4.11A, 4.30 снесено давно), есть такое - memcpy.c называется, и там вот такое (фрагмент):

#include <string.h>
_STD_BEGIN

void *(memcpy)(void *s1, const void *s2, size_t n)
    {    /* copy char s2[n] to s1[n] in any order */
    char *su1 = (char *)s1;
    const char *su2 = (const char *)s2;

    for (; 0 < n; ++su1, ++su2, --n)
        *su1 = *su2;
    return (s1);
    }
_STD_END

Я еще в IDA смотрел непосредственно скомпилированное/слинкованное - сильно от этого кода оно отличалось сейчас не скажу - не помню просто. Но от упомянутых MS-овских исходников или даже от GCC-шных отличия были значительные. Сейчас вот вытащил ABImemcpy.o из 5.41 - таки да, прогресс у них есть.

 

Вообще-то я хотел сказать, что совсем наоборот, и вроде так и сказал?

Ясно, значит я не понял, в том числе и эту фразу :)

 

 

Есть еще один сишный memcpy(). Интересно?

Вы уже на эту тему высказывались, и исходники выкладывали, я кое-чем оттуда попользовался даже :).

В предыдущем посте, пожалуйста, код в CODEBOX сверните, а то много текста - глаза разбегаются.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

aaarrr

Вы не могли бы добавить архивчик с исходником использованной в Ваших тестах memcpy()? Для полноты картины :)

Пожалуйста. Эта memcpy используется в ADS 1.2, RVDS 2.2 и RVDS 4.1. По всей видимости в ARM решили, что допиливать там больше нечего.

 

Никто бы не стал тестировать memcpy если б были исходники этой функции.

Почему же? У меня были, но все равно оказалось любопытно :)

 

__rt_memcpy
cmp	  r2,#3
bls	  _memcpy_lastbytes
ands	 r12,r0,#3
beq	  _memcpy_dest_aligned
ldrb	 r3,[r1],#1
cmp	  r12,#2
add	  r2,r2,r12
ldrlsb   r12,[r1],#1
strb	 r3,[r0],#1
ldrccb   r3,[r1],#1
strlsb   r12,[r0],#1
sub	  r2,r2,#4
strccb   r3,[r0],#1
_memcpy_dest_aligned
ands	 r3,r1,#3
beq	  __rt_memcpy_w
subs	 r2,r2,#4
bcc	  _memcpy_lastbytes
ldr	  r12,[r1,-r3]!
cmp	  r3,#2
beq	  _memcpy_src2_loop
bhi	  _memcpy_src3_loop
_memcpy_src1_loop
mov	  r3,r12,lsr #8
ldr	  r12,[r1,#4]!
subs	 r2,r2,#4
orr	  r3,r3,r12,lsl #24
str	  r3,[r0],#4
bcs	  _memcpy_src1_loop
add	  r1,r1,#1
b		_memcpy_lastbytes
_memcpy_src2_loop
mov	  r3,r12,lsr #16
ldr	  r12,[r1,#4]!
subs	 r2,r2,#4
orr	  r3,r3,r12,lsl #16
str	  r3,[r0],#4
bcs	  _memcpy_src2_loop
add	  r1,r1,#2
b		_memcpy_lastbytes
_memcpy_src3_loop
mov	  r3,r12,lsr #24
ldr	  r12,[r1,#4]!
subs	 r2,r2,#4
orr	  r3,r3,r12,lsl #8
str	  r3,[r0],#4
bcs	  _memcpy_src3_loop
add	  r1,r1,#3
b		_memcpy_lastbytes
__rt_memcpy_w
subs	 r2,r2,#0x20
stmfd	r13!,{r4,r14}
bcc	  _memcpy_small
_memcpy_aligned_loop
ldmcsia  r1!,{r3,r4,r12,r14}
stmcsia  r0!,{r3,r4,r12,r14}
ldmcsia  r1!,{r3,r4,r12,r14}
stmcsia  r0!,{r3,r4,r12,r14}
subcss   r2,r2,#0x20
bcs	  _memcpy_aligned_loop
_memcpy_small
movs	 r12,r2,lsl #28
ldmcsia  r1!,{r3,r4,r12,r14}
stmcsia  r0!,{r3,r4,r12,r14}
ldmmiia  r1!,{r3,r4}
stmmiia  r0!,{r3,r4}
movs	 r12,r2,lsl #30
ldmfd	r13!,{r4,r14}
ldrcs	r3,[r1],#4
strcs	r3,[r0],#4
moveq	pc,r14
_memcpy_lastbytes
movs	 r2,r2,lsl #31
ldrmib   r2,[r1],#1
ldrcsb   r3,[r1],#1
ldrcsb   r12,[r1],#1
strmib   r2,[r0],#1
strcsb   r3,[r0],#1
strcsb   r12,[r0],#1
mov	  pc,r14

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пожалуйста. Эта memcpy используется в ADS 1.2, RVDS 2.2 и RVDS 4.1. По всей видимости в ARM решили, что допиливать там больше нечего.

 

 

Почему же? У меня были, но все равно оказалось любопытно :)

 

 

Посмотрел сейчас дизассемблер в Keil-е. Ну не совпадает однако;) (у меня ARM926EJ-S)

У меня процедура заметно короче.

Да и как там совпасть? Компилер идет с кучей уже подготовленных либ под каждый нюанс архитектуры.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрел сейчас дизассемблер в Keil-е. Ну не совпадает однако;) (у меня ARM926EJ-S)

У меня процедура заметно короче.

Специально проверил - в точности совпадает. Только __rt_memcpy_w идет отдельным куском. Может, поэтому короче показалось?

 

Да и как там совпасть? Компилер идет с кучей уже подготовленных либ под каждый нюанс архитектуры.

Подходы к скоростному копированию на 7TDMI и 926EJ ну никак не отличаются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Из айфона. ARMv6:

_memcpy
			CMP			 R2, #0
			CMPNE		   R0, R1
			BXEQ			LR
			STMFD		   SP!, {R0,R4,R5,R7,LR}
			ADD			 R7, SP, #0xC
			SUBCS		   R3, R0, R1
			SUBCC		   R3, R1, R0
			CMP			 R3, R2
			BCC			 loc_319A9FF0
loc_319A9EA8
			MOV			 R12, R0,LSL#30
			CMP			 R12, R1,LSL#30
			BNE			 loc_319AA0D0
			CMP			 R2, #0x40
			BLT			 loc_319A9FC4
			TST			 R0, #0xF
			BNE			 loc_319A9F44
			TST			 R0, #0x10
			BNE			 loc_319A9F78
loc_319A9ECC
			STMFD		   SP!, {R6,R8,R10,R11}
			SUB			 R2, R2, #0x40
loc_319A9ED4
			LDMIA		   R1!, {R3-R6,R8,R10-R12}
			PLD			 [R1,#0x20]
			STMIA		   R0!, {R3-R6,R8,R10-R12}
			LDMIA		   R1!, {R3-R6,R8,R10-R12}
			SUBS			R2, R2, #0x40
			PLD			 [R1,#0x20]
			STMIA		   R0!, {R3-R6,R8,R10-R12}
			BGE			 loc_319A9ED4
			LDMFD		   SP!, {R6,R8,R10,R11}
			ADDS			R2, R2, #0x40
			BEQ			 locret_319AA1AC
loc_319A9F00
			CMP			 R2, #0x10
			LDMGEIA		 R1!, {R3-R5,R12}
			STMGEIA		 R0!, {R3-R5,R12}
			SUBGES		  R2, R2, #0x10
			BGT			 loc_319A9F00
			BEQ			 locret_319AA1AC
loc_319A9F18
			MOV			 R2, R2,LSL#28
			MSR			 CPSR_f, R2
			LDMMIIA		 R1!, {R2,R3}
			LDREQ		   R4, [R1],#4
			LDRCSH		  R5, [R1],#2
			LDRVSB		  R12, [R1],#1
			STMMIIA		 R0!, {R2,R3}
			STREQ		   R4, [R0],#4
			STRCSH		  R5, [R0],#2
			STRVSB		  R12, [R0],#1
			B			   locret_319AA1AC
; ---------------------------------------------------------------------------
loc_319A9F44
			MOV			 R12, R0,LSL#28
			RSB			 R12, R12, #0
			MSR			 CPSR_f, R12
			LDRVSB		  R3, [R1],#1
			LDRCSH		  R4, [R1],#2
			LDREQ		   R5, [R1],#4
			STRVSB		  R3, [R0],#1
			STRCSH		  R4, [R0],#2
			STREQ		   R5, [R0],#4
			LDMMIIA		 R1!, {R3,R4}
			STMMIIA		 R0!, {R3,R4}
			SUBS			R2, R2, R12,LSR#28
			BEQ			 locret_319AA1AC
loc_319A9F78
			TST			 R0, #0x10
			LDMNEIA		 R1!, {R3-R5,R12}
			STMNEIA		 R0!, {R3-R5,R12}
			SUBNE		   R2, R2, #0x10
			CMP			 R2, #0x40
			BGE			 loc_319A9ECC
			B			   loc_319A9F00
; ---------------------------------------------------------------------------
loc_319A9F94
			SUBS			R2, R2, #2
			LDRB			R3, [R1],#1
			LDRPLB		  R4, [R1],#1
			STRB			R3, [R0],#1
			STRPLB		  R4, [R0],#1
			BHI			 loc_319A9F94
			B			   locret_319AA1AC
; ---------------------------------------------------------------------------
loc_319A9FB0
			LDRB			R3, [R1],#1
			SUBS			R2, R2, #1
			STRB			R3, [R0],#1
			BNE			 loc_319A9FB0
			B			   locret_319AA1AC
; ---------------------------------------------------------------------------
loc_319A9FC4
			CMP			 R2, #4
			BLT			 loc_319A9F94
			TST			 R1, #3
loc_319A9FD0
			LDRNEB		  R3, [R1],#1
			STRNEB		  R3, [R0],#1
			SUBNE		   R2, R2, #1
			TSTNE		   R1, #3
			BNE			 loc_319A9FD0
			CMP			 R2, #0x10
			BGE			 loc_319A9F00
			BLT			 loc_319A9F18
loc_319A9FF0
			CMP			 R0, R1
			BHI			 loc_319AA00C
			CMP			 R3, #0x40
			BGE			 loc_319A9EA8
			CMP			 R3, #2
			BGE			 loc_319A9F94
			B			   loc_319A9FB0
; ---------------------------------------------------------------------------
loc_319AA00C
			ADD			 R0, R0, R2
			ADD			 R1, R1, R2
			CMP			 R2, #0x40
			CMPGT		   R3, #0x40
			BLT			 loc_319AA070
			MOV			 R3, R0,LSL#30
			CMP			 R3, R1,LSL#30
			BNE			 loc_319AA070
			TST			 R0, #0xF
			BNE			 loc_319AA084
			TST			 R0, #0x10
			BNE			 loc_319AA0B4
loc_319AA03C
			STMFD		   SP!, {R6,R8,R10,R11}
			SUB			 R2, R2, #0x40
loc_319AA044
			LDMDB		   R1!, {R3-R6,R8,R10-R12}
			PLD			 [R1,#-0x20]
			STMDB		   R0!, {R3-R6,R8,R10-R12}
			LDMDB		   R1!, {R3-R6,R8,R10-R12}
			SUBS			R2, R2, #0x40
			PLD			 [R1,#-0x20]
			STMDB		   R0!, {R3-R6,R8,R10-R12}
			BGE			 loc_319AA044
			LDMFD		   SP!, {R6,R8,R10,R11}
			ADDS			R2, R2, #0x40
			BEQ			 locret_319AA1AC
loc_319AA070
			LDRB			R3, [R1,#-1]!
			STRB			R3, [R0,#-1]!
			SUBS			R2, R2, #1
			BNE			 loc_319AA070
			B			   locret_319AA1AC
; ---------------------------------------------------------------------------
loc_319AA084
			MOV			 R12, R0,LSL#28
			MSR			 CPSR_f, R12
			LDRVSB		  R3, [R1,#-1]!
			LDRCSH		  R4, [R1,#-2]!
			LDREQ		   R5, [R1,#-4]!
			STRVSB		  R3, [R0,#-1]!
			STRCSH		  R4, [R0,#-2]!
			STREQ		   R5, [R0,#-4]!
			LDMMIDB		 R1!, {R3,R4}
			STMMIDB		 R0!, {R3,R4}
			SUBS			R2, R2, R12,LSR#28
			BEQ			 locret_319AA1AC
loc_319AA0B4
			TST			 R0, #0x10
			LDMNEDB		 R1!, {R3-R5,R12}
			STMNEDB		 R0!, {R3-R5,R12}
			SUBNE		   R2, R2, #0x10
			CMP			 R2, #0x40
			BGE			 loc_319AA03C
			B			   loc_319AA070
; ---------------------------------------------------------------------------
loc_319AA0D0
			CMP			 R2, #8
			BLT			 loc_319A9F94
			TST			 R1, #3
loc_319AA0DC
			LDRNEB		  R3, [R1],#1
			STRNEB		  R3, [R0],#1
			SUBNE		   R2, R2, #1
			TSTNE		   R1, #3
			BNE			 loc_319AA0DC
			AND			 R3, R0, #3
			CMP			 R3, #2
			BLT			 loc_319AA104
			BEQ			 loc_319AA138
			BGT			 loc_319AA16C
loc_319AA104
			MOV			 R12, R2,LSR#2
			SUB			 R0, R0, #1
			LDRB			R4, [R0]
loc_319AA110
			LDR			 R3, [R1],#4
			ORR			 R4, R4, R3,LSL#8
			STR			 R4, [R0],#4
			MOV			 R4, R3,LSR#24
			SUBS			R12, R12, #1
			BNE			 loc_319AA110
			STRB			R4, [R0],#1
			ANDS			R2, R2, #3
			BEQ			 locret_319AA1AC
			B			   loc_319A9F94
; ---------------------------------------------------------------------------
loc_319AA138
			MOV			 R12, R2,LSR#2
			SUB			 R0, R0, #2
			LDRH			R4, [R0]

loc_319AA144
			LDR			 R3, [R1],#4
			ORR			 R4, R4, R3,LSL#16
			STR			 R4, [R0],#4
			MOV			 R4, R3,LSR#16
			SUBS			R12, R12, #1
			BNE			 loc_319AA144
			STRH			R4, [R0],#2
			ANDS			R2, R2, #3
			BEQ			 locret_319AA1AC
			B			   loc_319A9F94
; ---------------------------------------------------------------------------
loc_319AA16C
			MOV			 R12, R2,LSR#2
			SUB			 R0, R0, #3
			LDR			 R4, [R0]
			BIC			 R4, R4, #0xFF000000

loc_319AA17C
			LDR			 R3, [R1],#4
			ORR			 R4, R4, R3,LSL#24
			STR			 R4, [R0],#4
			MOV			 R4, R3,LSR#8
			SUBS			R12, R12, #1
			BNE			 loc_319AA17C
			STRH			R4, [R0],#2
			MOV			 R4, R4,LSR#16
			STRB			R4, [R0],#1
			ANDS			R2, R2, #3
			BEQ			 locret_319AA1AC
			B			   loc_319A9F94
; ---------------------------------------------------------------------------
locret_319AA1AC
			LDMFD		   SP!, {R0,R4,R5,R7,PC}

ARMv7-A (Thumb-2/NEON):

_memmove	
			SUBS			R3, R0, R1
			IT EQ
			BXEQ			LR
			CMP			 R3, R2
			BCS.W		   loc_345C5EBC
			MOV			 R12, R0
			ADD			 R1, R2
			ADD			 R12, R2
			SUBS			R2, #8
			BLT			 loc_345C5DC0
			TST.W		   R12, #7
			BEQ			 loc_345C5CF2
loc_345C5CDC
			LDRB.W		  R3, [R1,#-1]!
			SUB.W		   R2, R2, #1
			STRB.W		  R3, [R12,#-1]!
			TST.W		   R12, #7
			BNE			 loc_345C5CDC
			CMP			 R2, #0
			BLT			 loc_345C5DC0
loc_345C5CF2
			ANDS.W		  R3, R1, #3; switch 4 cases
			BIC.W		   R1, R1, #3
			TBH.W		   [PC,R3,LSL#1]; switch jump
; ---------------------------------------------------------------------------
jpt_345C5CFA	DCW 4				  ; jump table for switch statement
			DCW 0x7C
			DCW 0x9D
			DCW 0xBE
; ---------------------------------------------------------------------------
loc_345C5D06
			SUBS			R2, #0x38; jumptable 345C5CFA case 0
			BLT			 loc_345C5DA8
			TST.W		   R12, #0x38
			BEQ			 loc_345C5D2E
loc_345C5D10
			SUB.W		   R1, R1, #8
			VLD1.32		 {D0}, [R1]
			SUB.W		   R12, R12, #8
			SUB.W		   R2, R2, #8
			TST.W		   R12, #0x38
			VST1.64		 {D0}, [R12@64]
			BNE			 loc_345C5D10
			CMP			 R2, #0
			BLT			 loc_345C5DA8
loc_345C5D2E
			SUB.W		   R3, R2, #0x3C0
			CMP.W		   R3, #0x7C00
			BCC			 loc_345C5DD4
			SUB.W		   R1, R1, #0x20
			SUB.W		   R12, R12, #0x20
			MOV			 R3, 0xFFFFFFE0
			TST.W		   R1, #0x1F
			BEQ			 loc_345C5D76
			VLD1.32		 {D4-D7}, [R1],R3
			VLD1.32		 {D0-D3}, [R1],R3
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256],R3
			BLT			 loc_345C5D9C
			NOP
			NOP
			NOP
loc_345C5D60
			VLD1.32		 {D4-D7}, [R1],R3
			VST1.64		 {D0-D3}, [R12@256],R3
			VLD1.32		 {D0-D3}, [R1],R3
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256],R3
			BGE			 loc_345C5D60
			B			   loc_345C5D9C
; ---------------------------------------------------------------------------
loc_345C5D76
			VLD1.64		 {D4-D7}, [R1@256],R3
			VLD1.64		 {D0-D3}, [R1@256],R3
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256],R3
			BLT			 loc_345C5D9C
			NOP
loc_345C5D88
			VLD1.64		 {D4-D7}, [R1@256],R3
			VST1.64		 {D0-D3}, [R12@256],R3
			VLD1.64		 {D0-D3}, [R1@256],R3
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256],R3
			BGE			 loc_345C5D88
loc_345C5D9C
			VST1.64		 {D0-D3}, [R12@256],R3
			ADD.W		   R1, R1, #0x20
			ADD.W		   R12, R12, #0x20
loc_345C5DA8
			ADDS			R2, #0x38
			BLT			 loc_345C5DC0
loc_345C5DAC
			SUB.W		   R1, R1, #8
			VLD1.32		 {D0}, [R1]
			SUB.W		   R12, R12, #8
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64]
			BGE			 loc_345C5DAC
loc_345C5DC0
			ADDS			R2, #8
			IT EQ
			BXEQ			LR
loc_345C5DC6
			LDRB.W		  R3, [R1,#-1]!
			SUBS			R2, #1
			STRB.W		  R3, [R12,#-1]!
			BNE			 loc_345C5DC6
			BX			  LR
; ---------------------------------------------------------------------------
loc_345C5DD4
			PUSH.W		  {R4-R6,R8,R10,R11}
loc_345C5DD8
			LDMDB.W		 R1!, {R3-R6,R8-R11}
			SUBS			R2, #0x40
			STMDB.W		 R12!, {R3-R6,R8-R11}
			LDMDB.W		 R1!, {R3-R6,R8-R11}
			PLD.W		   [R1,#-0x40]
			STMDB.W		 R12!, {R3-R6,R8-R11}
			BGE			 loc_345C5DD8
			POP.W		   {R4-R6,R8,R10,R11}
			B			   loc_345C5DA8
; ---------------------------------------------------------------------------
loc_345C5DF6
			SUBS			R2, #8 ; jumptable 345C5CFA case 1
			BLT			 loc_345C5E2E
			SUB.W		   R1, R1, #8
			SUB.W		   R12, R12, #8
			MOV			 R3, 0xFFFFFFF8
			VLD1.32		 {D2-D3}, [R1],R3
			SUBS			R2, #8
			BLT			 loc_345C5E22
loc_345C5E0E
			VEXT.8		  D0, D2, D3, #1
			VMOV			D3, D2
			VLD1.32		 {D2}, [R1],R3
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64],R3
			BGE			 loc_345C5E0E
loc_345C5E22
			VEXT.8		  D0, D2, D3, #1
			ADD.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]
loc_345C5E2E
			ADD.W		   R2, R2, #8
			ADD.W		   R1, R1, #1
			B			   loc_345C5DC0
; ---------------------------------------------------------------------------
loc_345C5E38
			SUBS			R2, #8 ; jumptable 345C5CFA case 2
			BLT			 loc_345C5E70
			SUB.W		   R1, R1, #8
			SUB.W		   R12, R12, #8
			MOV			 R3, 0xFFFFFFF8
			VLD1.32		 {D2-D3}, [R1],R3
			SUBS			R2, #8
			BLT			 loc_345C5E64
loc_345C5E50
			VEXT.8		  D0, D2, D3, #2
			VMOV			D3, D2
			VLD1.32		 {D2}, [R1],R3
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64],R3
			BGE			 loc_345C5E50
loc_345C5E64
			VEXT.8		  D0, D2, D3, #2
			ADD.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]
loc_345C5E70
			ADD.W		   R2, R2, #8
			ADD.W		   R1, R1, #2
			B			   loc_345C5DC0
; ---------------------------------------------------------------------------
loc_345C5E7A
			SUBS			R2, #8 ; jumptable 345C5CFA case 3
			BLT			 loc_345C5EB2
			SUB.W		   R1, R1, #8
			SUB.W		   R12, R12, #8
			MOV			 R3, 0xFFFFFFF8
			VLD1.32		 {D2-D3}, [R1],R3
			SUBS			R2, #8
			BLT			 loc_345C5EA6
loc_345C5E92
			VEXT.8		  D0, D2, D3, #3
			VMOV			D3, D2
			VLD1.32		 {D2}, [R1],R3
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64],R3
			BGE			 loc_345C5E92
loc_345C5EA6
			VEXT.8		  D0, D2, D3, #3
			ADD.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]
loc_345C5EB2
			ADD.W		   R2, R2, #8
			ADD.W		   R1, R1, #3
			B			   loc_345C5DC0
; ---------------------------------------------------------------------------
loc_345C5EBC
			MOV			 R12, R0
			SUBS			R2, #8
			BLT			 loc_345C5F88
			TST.W		   R12, #7
			BEQ			 loc_345C5EDE
loc_345C5EC8
			LDRB.W		  R3, [R1],#1
			SUB.W		   R2, R2, #1
			STRB.W		  R3, [R12],#1
			TST.W		   R12, #7
			BNE			 loc_345C5EC8
			CMP			 R2, #0
			BLT			 loc_345C5F88
loc_345C5EDE
			ANDS.W		  R3, R1, #3; switch 4 cases
			BIC.W		   R1, R1, #3
			TBH.W		   [PC,R3,LSL#1]; switch jump
; ---------------------------------------------------------------------------
jpt_345C5EE6	DCW 4				  ; jump table for switch statement
			DCW 0x6A
			DCW 0x85
			DCW 0xA0
; ---------------------------------------------------------------------------
loc_345C5EF2
			SUBS			R2, #0x38; jumptable 345C5EE6 case 0
			BLT			 loc_345C5F78
			TST.W		   R12, #0x38
			BEQ			 loc_345C5F12
loc_345C5EFC
			VLD1.32		 {D0}, [R1]!
			SUB.W		   R2, R2, #8
			VST1.64		 {D0}, [R12@64]!
			TST.W		   R12, #0x38
			BNE			 loc_345C5EFC
			CMP			 R2, #0
			BLT			 loc_345C5F78
loc_345C5F12
			SUB.W		   R3, R2, #0x3C0
			CMP.W		   R3, #0x7C00
			BCC			 loc_345C5F9C
			TST.W		   R1, #0x1F
			BEQ			 loc_345C5F4E
			VLD1.32		 {D4-D7}, [R1]!
			VLD1.32		 {D0-D3}, [R1]!
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256]!
			BLT			 loc_345C5F74
			NOP
			NOP
			NOP
loc_345C5F38
			VLD1.32		 {D4-D7}, [R1]!
			VST1.64		 {D0-D3}, [R12@256]!
			VLD1.32		 {D0-D3}, [R1]!
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256]!
			BGE			 loc_345C5F38
			B			   loc_345C5F74
; ---------------------------------------------------------------------------
loc_345C5F4E
			VLD1.64		 {D4-D7}, [R1@256]!
			VLD1.64		 {D0-D3}, [R1@256]!
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256]!
			BLT			 loc_345C5F74
			NOP
loc_345C5F60
			VLD1.64		 {D4-D7}, [R1@256]!
			VST1.64		 {D0-D3}, [R12@256]!
			VLD1.64		 {D0-D3}, [R1@256]!
			SUBS			R2, #0x40
			VST1.64		 {D4-D7}, [R12@256]!
			BGE			 loc_345C5F60
loc_345C5F74
			VST1.64		 {D0-D3}, [R12@256]!
loc_345C5F78
			ADDS			R2, #0x38
			BLT			 loc_345C5F88
loc_345C5F7C
			VLD1.32		 {D0}, [R1]!
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64]!
			BGE			 loc_345C5F7C
loc_345C5F88
			ADDS			R2, #8
			IT EQ
			BXEQ			LR
loc_345C5F8E
			LDRB.W		  R3, [R1],#1
			STRB.W		  R3, [R12],#1
			SUBS			R2, #1
			BNE			 loc_345C5F8E
			BX			  LR
; ---------------------------------------------------------------------------
loc_345C5F9C
			PUSH.W		  {R4-R6,R8,R10,R11}
loc_345C5FA0
			LDMIA.W		 R1!, {R3-R6,R8-R11}
			SUBS			R2, #0x40
			STMIA.W		 R12!, {R3-R6,R8-R11}
			LDMIA.W		 R1!, {R3-R6,R8-R11}
			PLD.W		   [R1,#0x40]
			STMIA.W		 R12!, {R3-R6,R8-R11}
			BGE			 loc_345C5FA0
			POP.W		   {R4-R6,R8,R10,R11}
			B			   loc_345C5F78
; ---------------------------------------------------------------------------
loc_345C5FBE
			SUBS			R2, #8 ; jumptable 345C5EE6 case 1
			BLT			 loc_345C5FEA
			VLD1.32		 {D2-D3}, [R1]!
			SUBS			R2, #8
			BLT			 loc_345C5FDE
loc_345C5FCA
			VEXT.8		  D0, D2, D3, #1
			VMOV			D2, D3
			VLD1.32		 {D3}, [R1]!
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64]!
			BGE			 loc_345C5FCA
loc_345C5FDE
			VEXT.8		  D0, D2, D3, #1
			SUB.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]!
loc_345C5FEA
			ADD.W		   R1, R1, #1
			ADD.W		   R2, R2, #8
			B			   loc_345C5F88
; ---------------------------------------------------------------------------
loc_345C5FF4
			SUBS			R2, #8
			BLT			 loc_345C6020
			VLD1.32		 {D2-D3}, [R1]!
			SUBS			R2, #8
			BLT			 loc_345C6014
loc_345C6000
			VEXT.8		  D0, D2, D3, #2
			VMOV			D2, D3
			VLD1.32		 {D3}, [R1]!
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64]!
			BGE			 loc_345C6000
loc_345C6014
			VEXT.8		  D0, D2, D3, #2
			SUB.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]!
loc_345C6020
			ADD.W		   R1, R1, #2
			ADD.W		   R2, R2, #8
			B			   loc_345C5F88
; ---------------------------------------------------------------------------
loc_345C602A
			SUBS			R2, #8
			BLT			 loc_345C6056
			VLD1.32		 {D2-D3}, [R1]!
			SUBS			R2, #8
			BLT			 loc_345C604A
loc_345C6036
			VEXT.8		  D0, D2, D3, #3
			VMOV			D2, D3
			VLD1.32		 {D3}, [R1]!
			SUBS			R2, #8
			VST1.64		 {D0}, [R12@64]!
			BGE			 loc_345C6036
loc_345C604A
			VEXT.8		  D0, D2, D3, #3
			SUB.W		   R1, R1, #8
			VST1.64		 {D0}, [R12@64]!
loc_345C6056
			ADD.W		   R1, R1, #3
			ADD.W		   R2, R2, #8
			B			   loc_345C5F88

Изменено пользователем igorsk

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Самый шустрый memcpy для всех случаев выравненных/невыравненных данных - в NetBSD (написан на ассемблере).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Самый шустрый memcpy для всех случаев выравненных/невыравненных данных - в NetBSD (написан на ассемблере).

Этот?

/*	$NetBSD: memcpy_arm.S,v 1.1 2003/10/14 07:51:45 scw Exp $	*/

/*-
* Copyright © 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*        This product includes software developed by the NetBSD
*        Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
*    contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <machine/asm.h>
__FBSDID("$FreeBSD: src/lib/libc/arm/string/memcpy_arm.S,v 1.1 2004/05/14 12:04:31 cognet Exp $");
/*
* This is one fun bit of code ...
* Some easy listening music is suggested while trying to understand this
* code e.g. Iron Maiden
*
* For anyone attempting to understand it :
*
* The core code is implemented here with simple stubs for memcpy().
*
* All local labels are prefixed with Lmemcpy_
* Following the prefix a label starting f is used in the forward copy code
* while a label using b is used in the backwards copy code
* The source and destination addresses determine whether a forward or
* backward copy is performed.
* Separate bits of code are used to deal with the following situations
* for both the forward and backwards copy.
* unaligned source address
* unaligned destination address
* Separate copy routines are used to produce an optimised result for each
* of these cases.
* The copy code will use LDM/STM instructions to copy up to 32 bytes at
* a time where possible.
*
* Note: r12 (aka ip) can be trashed during the function along with
* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
* Additional registers are preserved prior to use i.e. r4, r5 & lr
*
* Apologies for the state of the comments ;-)
*/
/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */
ENTRY(memcpy)
/* save leaf functions having to store this away */
stmdb	sp!, {r0, lr}		/* memcpy() returns dest addr */

subs	r2, r2, #4
blt	.Lmemcpy_l4		/* less than 4 bytes */
ands	r12, r0, #3
bne	.Lmemcpy_destul		/* oh unaligned destination addr */
ands	r12, r1, #3
bne	.Lmemcpy_srcul		/* oh unaligned source addr */

.Lmemcpy_t8:
/* We have aligned source and destination */
subs	r2, r2, #8
blt	.Lmemcpy_l12		/* less than 12 bytes (4 from above) */
subs	r2, r2, #0x14         
blt	.Lmemcpy_l32		/* less than 32 bytes (12 from above) */
stmdb	sp!, {r4}		/* borrow r4 */

/* blat 32 bytes at a time */
/* XXX for really big copies perhaps we should use more registers */
.Lmemcpy_loop32:	
ldmia	r1!, {r3, r4, r12, lr}
stmia	r0!, {r3, r4, r12, lr}
ldmia	r1!, {r3, r4, r12, lr}
stmia	r0!, {r3, r4, r12, lr}
subs	r2, r2, #0x20         
bge	.Lmemcpy_loop32

cmn	r2, #0x10
ldmgeia	r1!, {r3, r4, r12, lr}	/* blat a remaining 16 bytes */
stmgeia	r0!, {r3, r4, r12, lr}
subge	r2, r2, #0x10         
ldmia	sp!, {r4}		/* return r4 */

.Lmemcpy_l32:
adds	r2, r2, #0x14         

/* blat 12 bytes at a time */
.Lmemcpy_loop12:
ldmgeia	r1!, {r3, r12, lr}
stmgeia	r0!, {r3, r12, lr}
subges	r2, r2, #0x0c         
bge	.Lmemcpy_loop12

.Lmemcpy_l12:
adds	r2, r2, #8
blt	.Lmemcpy_l4

subs	r2, r2, #4
ldrlt	r3, [r1], #4
strlt	r3, [r0], #4
ldmgeia	r1!, {r3, r12}
stmgeia	r0!, {r3, r12}
subge	r2, r2, #4

.Lmemcpy_l4:
/* less than 4 bytes to go */
adds	r2, r2, #4
#ifdef __APCS_26_
ldmeqia sp!, {r0, pc}^		/* done */
#else
ldmeqia	sp!, {r0, pc}		/* done */
#endif
/* copy the crud byte at a time */
cmp	r2, #2
ldrb	r3, [r1], #1
strb	r3, [r0], #1
ldrgeb	r3, [r1], #1
strgeb	r3, [r0], #1
ldrgtb	r3, [r1], #1
strgtb	r3, [r0], #1
ldmia	sp!, {r0, pc}

/* erg - unaligned destination */
.Lmemcpy_destul:
rsb	r12, r12, #4
cmp	r12, #2

/* align destination with byte copies */
ldrb	r3, [r1], #1
strb	r3, [r0], #1
ldrgeb	r3, [r1], #1
strgeb	r3, [r0], #1
ldrgtb	r3, [r1], #1
strgtb	r3, [r0], #1
subs	r2, r2, r12
blt	.Lmemcpy_l4		/* less the 4 bytes */

ands	r12, r1, #3
beq	.Lmemcpy_t8		/* we have an aligned source */

/* erg - unaligned source */
/* This is where it gets nasty ... */
.Lmemcpy_srcul:
bic	r1, r1, #3
ldr	lr, [r1], #4
cmp	r12, #2
bgt	.Lmemcpy_srcul3
beq	.Lmemcpy_srcul2
cmp	r2, #0x0c            
blt	.Lmemcpy_srcul1loop4
sub	r2, r2, #0x0c         
stmdb	sp!, {r4, r5}

.Lmemcpy_srcul1loop16:
#ifdef __ARMEB__
mov	r3, lr, lsl #8
#else
mov	r3, lr, lsr #8
#endif
ldmia	r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr	r3, r3, r4, lsr #24
mov	r4, r4, lsl #8
orr	r4, r4, r5, lsr #24
mov	r5, r5, lsl #8
orr	r5, r5, r12, lsr #24
mov	r12, r12, lsl #8
orr	r12, r12, lr, lsr #24
#else
orr	r3, r3, r4, lsl #24
mov	r4, r4, lsr #8
orr	r4, r4, r5, lsl #24
mov	r5, r5, lsr #8
orr	r5, r5, r12, lsl #24
mov	r12, r12, lsr #8
orr	r12, r12, lr, lsl #24
#endif
stmia	r0!, {r3-r5, r12}
subs	r2, r2, #0x10         
bge	.Lmemcpy_srcul1loop16
ldmia	sp!, {r4, r5}
adds	r2, r2, #0x0c         
blt	.Lmemcpy_srcul1l4

.Lmemcpy_srcul1loop4:
#ifdef __ARMEB__
mov	r12, lr, lsl #8
#else
mov	r12, lr, lsr #8
#endif
ldr	lr, [r1], #4
#ifdef __ARMEB__
orr	r12, r12, lr, lsr #24
#else
orr	r12, r12, lr, lsl #24
#endif
str	r12, [r0], #4
subs	r2, r2, #4
bge	.Lmemcpy_srcul1loop4

.Lmemcpy_srcul1l4:
sub	r1, r1, #3
b	.Lmemcpy_l4

.Lmemcpy_srcul2:
cmp	r2, #0x0c            
blt	.Lmemcpy_srcul2loop4
sub	r2, r2, #0x0c         
stmdb	sp!, {r4, r5}

.Lmemcpy_srcul2loop16:
#ifdef __ARMEB__
mov	r3, lr, lsl #16
#else
mov	r3, lr, lsr #16
#endif
ldmia	r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr	r3, r3, r4, lsr #16
mov	r4, r4, lsl #16
orr	r4, r4, r5, lsr #16
mov	r5, r5, lsl #16
orr	r5, r5, r12, lsr #16
mov	r12, r12, lsl #16
orr	r12, r12, lr, lsr #16
#else
orr	r3, r3, r4, lsl #16
mov	r4, r4, lsr #16
orr	r4, r4, r5, lsl #16
mov	r5, r5, lsr #16
orr	r5, r5, r12, lsl #16
mov	r12, r12, lsr #16
orr	r12, r12, lr, lsl #16
#endif
stmia	r0!, {r3-r5, r12}
subs	r2, r2, #0x10         
bge	.Lmemcpy_srcul2loop16
ldmia	sp!, {r4, r5}
adds	r2, r2, #0x0c         
blt	.Lmemcpy_srcul2l4

.Lmemcpy_srcul2loop4:
#ifdef __ARMEB__
mov	r12, lr, lsl #16
#else
mov	r12, lr, lsr #16
#endif
ldr	lr, [r1], #4
#ifdef __ARMEB__
orr	r12, r12, lr, lsr #16
#else
orr	r12, r12, lr, lsl #16
#endif
str	r12, [r0], #4
subs	r2, r2, #4
bge	.Lmemcpy_srcul2loop4

.Lmemcpy_srcul2l4:
sub	r1, r1, #2
b	.Lmemcpy_l4

.Lmemcpy_srcul3:
cmp	r2, #0x0c            
blt	.Lmemcpy_srcul3loop4
sub	r2, r2, #0x0c         
stmdb	sp!, {r4, r5}

.Lmemcpy_srcul3loop16:
#ifdef __ARMEB__
mov	r3, lr, lsl #24
#else
mov	r3, lr, lsr #24
#endif
ldmia	r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr	r3, r3, r4, lsr #8
mov	r4, r4, lsl #24
orr	r4, r4, r5, lsr #8
mov	r5, r5, lsl #24
orr	r5, r5, r12, lsr #8
mov	r12, r12, lsl #24
orr	r12, r12, lr, lsr #8
#else
orr	r3, r3, r4, lsl #8
mov	r4, r4, lsr #24
orr	r4, r4, r5, lsl #8
mov	r5, r5, lsr #24
orr	r5, r5, r12, lsl #8
mov	r12, r12, lsr #24
orr	r12, r12, lr, lsl #8
#endif
stmia	r0!, {r3-r5, r12}
subs	r2, r2, #0x10         
bge	.Lmemcpy_srcul3loop16
ldmia	sp!, {r4, r5}
adds	r2, r2, #0x0c         
blt	.Lmemcpy_srcul3l4

.Lmemcpy_srcul3loop4:
#ifdef __ARMEB__
mov	r12, lr, lsl #24
#else
mov	r12, lr, lsr #24
#endif
ldr	lr, [r1], #4
#ifdef __ARMEB__
orr	r12, r12, lr, lsr #8
#else
orr	r12, r12, lr, lsl #8
#endif
str	r12, [r0], #4
subs	r2, r2, #4
bge	.Lmemcpy_srcul3loop4

.Lmemcpy_srcul3l4:
sub	r1, r1, #1
b	.Lmemcpy_l4

 

Ну, для случая выровненных данных он быстрее не будет - цикл тот же. А вот перепаковка не выровненных сделана похитрее. Сейчас посмотрим.

 

Сейчас посмотрим.

Что и следовало ожидать:

copy[0][0]: 60.672
copy[1][0]: 51.689
copy[2][0]: 51.689
copy[3][0]: 51.689

copy[0][1]: 56.880
copy[1][1]: 55.245
copy[2][1]: 51.687
copy[3][1]: 51.689

copy[0][2]: 56.879
copy[1][2]: 51.689
copy[2][2]: 55.245
copy[3][2]: 51.687

copy[0][3]: 56.880
copy[1][3]: 51.687
copy[2][3]: 51.687
copy[3][3]: 55.245

Операции с не выравненными данными ускорились. И местами даже обгоняют таковые при одинаковом выравнивании.

 

Сейчас поставим еще один эксперимент: уроним частоту шины памяти в два раза, чтобы приблизиться к современному отношению частоты ядра к частоте шины.

 

В два раза не стал, остановился на соотношении 1/3:

 

memcpy_rvct

copy[0][0]: 41.713
copy[1][0]: 33.708
copy[2][0]: 33.708
copy[3][0]: 33.708

copy[0][1]: 30.337
copy[1][1]: 36.830
copy[2][1]: 33.707
copy[3][1]: 33.707

copy[0][2]: 30.337
copy[1][2]: 30.337
copy[2][2]: 36.830
copy[3][2]: 33.707

copy[0][3]: 30.337
copy[1][3]: 30.337
copy[2][3]: 30.336
copy[3][3]: 36.830

 

memcpy_bsd

copy[0][0]: 41.712
copy[1][0]: 35.392
copy[2][0]: 35.392
copy[3][0]: 35.392

copy[0][1]: 40.028
copy[1][1]: 36.830
copy[2][1]: 35.391
copy[3][1]: 35.391

copy[0][2]: 40.026
copy[1][2]: 35.391
copy[2][2]: 36.830
copy[3][2]: 35.391

copy[0][3]: 40.026
copy[1][3]: 35.391
copy[2][3]: 35.391
copy[3][3]: 36.830

 

Итого: memcpy из NetBSD - хорошая, годная процедура. Но данные все равно лучше выравнивать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...