如何在汇编函数中将元素数组作为参数传递时转发ARM寄存器的地址指针
Posted
技术标签:
【中文标题】如何在汇编函数中将元素数组作为参数传递时转发ARM寄存器的地址指针【英文标题】:How to make forward the address pointer of ARM register while passing array of elements as parameter in an assembly function 【发布时间】:2017-08-24 06:46:46 【问题描述】:作为一名汇编语言领域的新手开发人员,我正在尝试编写几个 arm neon 函数来加快计算速度。我将附上两个代码片段来解释我的问题。
void CalculateSumOfLast64(unsigned int *pData, unsigned int *ans)
unsigned int *pDataTemp = pData + 192;
int sum = 0;
for(int i=0; i<64; i++)
sum += pDataTemp[i];
*ans = sum;
int main()
unsigned int *pData = new unsigned int[256]; //Always Length is 256
for(int i=0;i<256;i++)
pData[i] = rand()%256;
unsigned int *ans = new unsigned int[1];
CalculateSumOfLast64(pData, ans);
cout<<"Final Ans = "<<*ans<<endl;
return 0;
在这里,我试图计算元素数组中最后 64 个值的总和。我已经通过使用 arm neon 指令集转换了这个函数。
NEON_ASM_FUNC_BEGIN CalculateSumOfLast64_ARM_NEON
#r0 First parameter, This is the address of <pData>
#r1 Second Parameter, This is the address of <ans>
push r2-r8, lr
mov r4, r0
mov r5, #192
.skipLoop:
vld1.u32 d0, [r4]!
subs r5, #2
bne .skipLoop
mov r8, #0
mov r5, #64
.calculationLoop:
vld1.u32 d0, [r4]!
vmov r7, r6, d0
add r8, r8, r6;
add r8, r8, r7;
subs r5, #2
bne .calculationLoop
str r8, [r1]
pop r2-r8, pc
NEON_ASM_FUNC_END
在c++中前进或操作地址指针真的很容易。
unsigned int *pDataTemp = pData + 192;
我需要一个完整的循环来移动手臂寄存器中的地址指针。
mov r5, #192
.skipLoop:
vld1.u32 d0, [r4]!
subs r5, #2
bne .skipLoop
虽然这个解决方案有效,但我知道……这绝对不是一个好主意。 我在网上搜索了很多以提出解决方案。 是否有任何指令集可以转发arm寄存器的地址指针? 或者,这个问题有没有更好的解决方案?
【问题讨论】:
这是不正确的。它的工作方式类似于r4 = r4 + r5 * 2
,这似乎是您想要的。请注意,如果您只想将 r4
提升 192 个位置,则可以执行 add r4,r4,#768
。
@fuz,是的,你是对的。 add r4, r4, r5, LSL #1 指令的工作方式类似于 r4 = r4 + r5 * 2。但是 add r4, r4, #768 指令似乎 r4 = r4 + 768。你确定它会将寄存器地址推进192个职位。我有点困惑,因为我不明白它是如何工作的。你能解释一下吗?
192 * 4 = 768。内存可按单字节寻址,而您的元素有 4 个字节长,因此要移动 192 个元素位置,您必须将地址增加 4*192。 (顺便说一句,编译器不能设置为使用霓虹灯指令和矢量化优化步骤吗?它很可能会比你更快(或更正确)产生一些东西)
好的,数字 768 是要前进的总字节数。但在这种情况下,添加 r4,r4,#768 似乎会将寄存器 r4 当前指向的值增加 768。如果我错了,请澄清。
r4
是寄存器r4
的内容,是32位值。 [r4]
是内存内容,由r4
值寻址(因此在这种情况下,r4
被解释为内存地址)。在add r4,r4,#768
中,r4
的 32 位被解释并用作 32 位整数数值,因此如果有地址指向数组的第一个元素(在 C 中 pData + 0
值),则将添加 768,在 C 语言中,如 (int*)(((byte*)pData) + 768)
。如果pData
是int*
类型,则等于pData + 192
。 C 通过使用已知的数据类型大小来乘以索引来“帮助”指针算术。 Asm 没有
【参考方案1】:
不要只是移动,而是在开头添加:
add r4, r0, #192*4
这样就可以了。
【讨论】:
【参考方案2】:C++ 示例: 在 c++ 中前进或操作地址指针真的很容易。
void testFunc(unsigned int *pData)
//Move address if needed...and do calculations..
unsigned int *pDataNew = pData + 192;
装配示例: 在汇编中,我们可以按照以下指令集执行操作。
ADD R7, R0, #192*4
解释: 这条指令可用于加值和加内存地址i)我们假设R0寄存器代表一个值。例如,R0 = 598。然后ADD R7, R0, #192*4 指令的工作方式类似于R7 = 598 + 192 * 4 = 1366。R7 将代表另一个值。 ii) 假设 R0 寄存器代表一个内存地址。 例如,R0 = 0xcbc02150(内存地址取决于 ARCH)。 然后 ADD R7, R0, #192*4 指令将像R7 = 0xCBC02150 + HexValue(192*4) = 0xCBC02150 + 0x300 = 0xCBC02450一样工作。 R7 将代表另一个内存地址。
【讨论】:
添加整数与添加指针不是“不同的任务”。在汇编语言中,指针只是整数。 (此外,您示例中的地址是 48 位的,这很奇怪。) @PeterCordes,感谢您的评论。我已按照您的建议编辑了答案。 :) 太棒了。很久以前给你最正确的答案,你自己回答,自己挑。现在你可以猜到了:我以后会回答你的问题吗? @Jake Alquimista Lee,对不起,兄弟……我不是故意要伤害你的。我只是试图用一些解释来详细说明答案。我刚刚接受了你的回答。 :)以上是关于如何在汇编函数中将元素数组作为参数传递时转发ARM寄存器的地址指针的主要内容,如果未能解决你的问题,请参考以下文章