[英]arm assembly memset replacement
我是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;
}
有四個寄存器的stmia
寫入16個字節,所以兩次寫入32個字節。 您將16添加到指向32位值的指針,每次有效地添加64,因此會有漏洞。
此外,ARM沒有32位立即數,但許多匯編程序通過在函數后面的特殊區域生成數據字段並將mov
轉換為PC相對的ldr
。 檢查生成的匯編器輸出是否可能在指令流的中間生成該字段。
另外,您可以在匯編器中生成32位值:
mov r4, %[mask]
orr r4, r4, r4 lsl #16
orr r4, r4, r4 lsl #8
由於這是一個8位立即數,它適合,並且不需要生成ldr
。
當你在它時,只需將整個循環拉入匯編程序,這樣你就可以重用地址寄存器。 眾所周知,gcc不能優化包含內聯匯編程序的例程。
那是錯字嗎:
:: [dst] "r" (d), [flag] "r" (&setflag32) : "r4", "r4", "r6", "r7");
您不是在說"r4", "r5", "r6" ...
嗎?
你的自制memset會比原來的memset快嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.