aaarrr 69 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Надо будет проверить влияние этого на производительность. Проверил интереса для. Должен сказать, что результаты вышли довольно любопытные, поэтому решил изложить их здесь. В ходе эксперимента измерялась скорость копирования 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). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Тут важнее каким компилером это делалось и какая шина была к SDRAM. С другой стороны в драйверах где скорость особенно важна практически нет свободы выбора как будут размещены приходящие в драйвер данные. Зато есть свобода выбора компилятора ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Тут важнее каким компилером это делалось и какая шина была к SDRAM. Я бы сказал что не от компилятора, а от конкретной реализации memcpy() - она обычно на ассемблере пишется, компилятор никак не результат повлиять не может. aaarrr Вы не могли бы добавить архивчик с исходником использованной в Ваших тестах memcpy()? Для полноты картины :) Про разные банки - эффект известный, Ваш тест очень хорошо его отобразил. Только пользоваться этим эффектом трудно, у тех контроллеров что мне попадались, биты адреса банка замешивались в середину физического адреса. И получалось что в адресном пространстве подряд шли страницы из разных банков, да еще они могли на разных платах быть разного размера - в зависимости от того какие чипы запаяли. В среднем (когда не задумываться о банках) это наверное эффективней, тем более в DDR2 банков уже может быть 8. Но при этом сознательно "разбанковать" данные становится трудновато. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Я бы сказал что не от компилятора, а от конкретной реализации memcpy() - она обычно на ассемблере пишется, компилятор никак не результат повлиять не может. Почему вы решили что все пишут на GCC? Ни в IAR, ни в Keil, ни в GHS, ни в RealView исходники memcpy недоступны. Никто бы не стал тестировать memcpy если б были исходники этой функции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Ни в IAR, ни в Keil, ни в GHS, ни в RealView исходники memcpy недоступны. MS - доступны я ими когда-то пользовался, ибо в IAR 4x был мрак с memcpy(), но IAR - для 4x и 5.x день и ночь по результатам. Keil - не знаю что там, но под drystone :) он когда-то славно подточен был. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Почему вы решили что все пишут на GCC? Ни в IAR, Надо признать, резон в замечании есть. Тут дело не столько в GCC, сколько в том, что memcpy() лично для меня функция важная и тщательно изученная не для одной архитектуры. Вот я и решил что все ее код "знают в лицо". Был неправ, что сказать . BTW, для IAR Full версии исходники доступны, и это они зря - там грустно :( Никто бы не стал тестировать memcpy если б были исходники этой функции. Исходники (ессно, в нормальном варианте) там бывают довольно любопытные - иногда я много нового узнаю :). ИМХО, тестировать memcpy() следует потому что на современных системах производительность зависит не только (далеко не только) от того что написано в исходнике этой функции. Лично я всегда при помощи тестов memcpy() (своей имплементации RTL) тюнингую настройки контроллера DRAM, арбитра шины и прочие подобные мелочи. ибо в IAR 4x был мрак с memcpy(), но IAR - для 4x и 5.x день и ночь по результатам. Э-э-э-э, то есть 5-ый еще хуже чем 4-ый? Да куда ж там дальше-то. Я последний раз IAR-овские исходники смотрел в 4.30 - правда мрак. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба 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(). Интересно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VslavX 0 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Э,то что Вам показалось исходниками, это не они, это какая-то заглушка. Исходников нет и в полной. Да вроде специально глянул (в 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 69 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Пожалуйста. Эта memcpy используется в ADS 1.2, RVDS 2.2 и RVDS 4.1. По всей видимости в ARM решили, что допиливать там больше нечего. Почему же? У меня были, но все равно оказалось любопытно :) Посмотрел сейчас дизассемблер в Keil-е. Ну не совпадает однако;) (у меня ARM926EJ-S) У меня процедура заметно короче. Да и как там совпасть? Компилер идет с кучей уже подготовленных либ под каждый нюанс архитектуры. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Посмотрел сейчас дизассемблер в Keil-е. Ну не совпадает однако;) (у меня ARM926EJ-S) У меня процедура заметно короче. Специально проверил - в точности совпадает. Только __rt_memcpy_w идет отдельным куском. Может, поэтому короче показалось? Да и как там совпасть? Компилер идет с кучей уже подготовленных либ под каждый нюанс архитектуры. Подходы к скоростному копированию на 7TDMI и 926EJ ну никак не отличаются. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
igorsk 0 22 августа, 2010 Опубликовано 22 августа, 2010 (изменено) · Жалоба Из айфона. 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 Изменено 22 августа, 2010 пользователем igorsk Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Самый шустрый memcpy для всех случаев выравненных/невыравненных данных - в NetBSD (написан на ассемблере). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 22 августа, 2010 Опубликовано 22 августа, 2010 · Жалоба Самый шустрый 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 - хорошая, годная процедура. Но данные все равно лучше выравнивать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 23 августа, 2010 Опубликовано 23 августа, 2010 · Жалоба Но данные все равно лучше выравнивать. Это очевидный факт для ARM. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться