замена комплекта рычагов в сборе - PullRequest
1 голос
/ 23 февраля 2012

Я новичок в сборке ARM, так что держись со мной.Я пишу приложение для визуализации музыки для Android.Я нахожусь в точке, где я хочу работать над оптимизацией, так что сейчас я как бы экспериментирую.Ниже моя попытка 8-битной гибридной реализации memset ASM и C.

Где-то это вызывает сбой.Я не могу подключить GDB к процессу, потому что приложение закрывается до запуска GDB, поэтому я не могу выполнить операции.

Это выглядит правильно?Я никогда не был полностью занят выравниванием памяти, но я знаю, что ARM выровнен на 4 байта.Я не уверен, является ли это подсказкой к решению или нет.Я думаю, что гибридный подход, состоящий в том, чтобы разместить большую часть операций в цикле сборки, а затем завершить его до 8 байт за проход, решает любые проблемы с выравниванием.Правильно ли я думаю об этом?Я озадачен тем, что происходит не так.Это действительно похоже на функцию memcpy, и моей единственной проблемой в то время было то, что список клоббера был пуст.Добавление этих регистров в список clobber завершило работу функции, и я просто не могу понять, чего мне не хватает с этой функцией memset.

Любые подсказки?

* Memset functions, 1 byte memset */
static void *mem_set8_arm (void *dest, int c, visual_size_t n)
{
    uint32_t *d = dest;
    uint8_t *dc = dest;
    uint32_t setflag32 =
        (c & 0xff) |
        ((c << 8) & 0xff00) |
        ((c << 16) & 0xff0000) |
        ((c << 24) & 0xff000000);
    uint8_t setflag8 = c & 0xff;

#if defined(VISUAL_ARCH_ARM)

    while (n >= 64) {
        __asm __volatile
        (
            "\n\t mov r4, %[flag]"
            "\n\t mov r5, r4"
            "\n\t mov r6, r4"
            "\n\t mov r7, r4"
            "\n\t stmia %[dst]!,{r4-r7}"
            "\n\t stmia %[dst]!,{r4-r7}"
        :: [dst] "r" (d), [flag] "r" (&setflag32) : "r4", "r4", "r6", "r7");

        d += 16;

        n -= 64;
    }

#endif /* VISUAL_ARCH_ARM */

    while (n >= 4) {
        *d++ = setflag32;
        n -= 4;
    }

    dc = (uint8_t *) d;

    while (n--)
        *dc++ = setflag8;

    return dest;
}

Ответы [ 2 ]

2 голосов
/ 23 февраля 2012

stmia с четырьмя регистрами записывает 16 байтов, поэтому, делая это дважды, записывает 32 байта. Вы добавляете 16 к указателю к 32-битным значениям, эффективно добавляя 64 каждый раз, так что будут дыры.

Кроме того, ARM не имеет 32-битных непосредственных операторов, но многие ассемблеры обходят это, генерируя поле данных в специальной области за функцией и превращая mov в относительную к ПК ldr. Проверьте сгенерированный вывод ассемблера, возможно, это поле было сгенерировано в середине потока команд.

Кроме того, вы можете просто сгенерировать 32-битное значение в ассемблере:

mov r4, %[mask]
orr r4, r4, r4 lsl #16
orr r4, r4, r4 lsl #8

Поскольку это 8-битное значение, оно подходит, и ldr генерировать не нужно.

Пока вы это делаете, просто вытяните весь цикл в ассемблер, чтобы вы могли повторно использовать регистр адресов. Общеизвестно, что gcc оптимизирует подпрограммы, содержащие встроенный ассемблер.

1 голос
/ 23 февраля 2012

Это опечатка:

:: [dst] "r" (d), [flag] "r" (&setflag32) : "r4", "r4", "r6", "r7");

Разве вы не имели в виду "r4", "r5", "r6" ... там?

Будет ли ваш самодельный memset действительно быстрее оригинального memset?

...