臂组件memset更换

时间:2012-02-23 11:40:37

标签: c gcc assembly arm

我是ARM装配的新手,对我来说很光鲜。我正在为Android编写音乐可视化应用程序。我正处于我想要优化的地方,所以现在我正在尝试。下面是我对8位memset混合ASM和C实现的尝试。

某处导致崩溃。我无法将gdb附加到进程,因为该应用程序 在gdb启动之前退出,因此我无法单步执行操作。

这看起来不错吗?我从来没有完全围绕内存对齐,但我知道ARM是4字节对齐。我不确定这是否是对解决方案的暗示。我认为混合方法是在一个汇编循环中堆叠大部分操作,然后每次传递8个字节完成它,可以解决任何对齐问题。我在想这个是正确的吗?我对于出了什么问题感到困惑。这与memcpy函数非常类似,我当时唯一的问题是clobber列表是空的。将这些寄存器添加到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 个答案:

答案 0 :(得分:2)

带有四个寄存器的

stmia写入16个字节,因此两次写入写入32个字节。你正在向一个指向32位值的指针添加16,每次有效地增加64,所以会有漏洞。

此外,ARM没有32位立即数,但很多汇编程序通过在函数后面的特殊区域生成数据字段并将mov转换为PC相对{{1}来解决这个问题。 }。检查生成的汇编器输出是否可能在指令流的中间生成该字段。

此外,您只需在汇编程序中生成32位值:

ldr

由于这是一个8位立即数,它适合,并且不需要生成mov r4, %[mask] orr r4, r4, r4 lsl #16 orr r4, r4, r4 lsl #8

当你在它时,只需将整个循环拉入汇编程序,这样你就可以重用地址寄存器。 gcc在优化包含内联汇编程序的例程方面非常糟糕。

答案 1 :(得分:1)

这是一个错字:

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

你的意思不是"r4", "r5", "r6" ...吗?

你的自制memset会不会比原来的memset更快?