Algorithm 臂组件的PRNG?
我在为手臂装配实现PRNG时遇到问题。我尝试过一些算法,在工作时,在最初的几次随机数迭代之后需要很长时间,可能是因为除法(模)步骤在大数上需要很长时间。我试图得到一个介于0和31之间的随机数。我在下面给出了我的粗略工作,用信件代替了特定的登记簿 开始:Algorithm 臂组件的PRNG?,algorithm,assembly,random,arm,Algorithm,Assembly,Random,Arm,我在为手臂装配实现PRNG时遇到问题。我尝试过一些算法,在工作时,在最初的几次随机数迭代之后需要很长时间,可能是因为除法(模)步骤在大数上需要很长时间。我试图得到一个介于0和31之间的随机数。我在下面给出了我的粗略工作,用信件代替了特定的登记簿 开始: mov t, x // t = x // t ^= t << 11 lsl temp, t, #11 eor t, temp // t ^= t >> 8 lsr temp, t, #8 eor
mov t, x // t = x
// t ^= t << 11
lsl temp, t, #11
eor t, temp
// t ^= t >> 8
lsr temp, t, #8
eor t, temp
// z = w
mov z, w
// x = y
mov x, y
// y = z
mov y, z
// w ^= w >> 19
lsr temp, w, #19
eor w, temp
// w ^= t
eor w, t
// result is the RETURNED RANDOM NUMBER
mov result, w
movt,x//t=x
//t^=t>8
lsr温度,t,#8
三次采油温度
//z=w
莫夫z,w
//x=y
mov x,y
//y=z
莫夫y,z
//w^=w>>19
lsr温度,w,#19
提高采收率,温度
//w^=t
提高采收率w,t
//结果是返回的随机数
mov结果,w
这是我在维基百科的XORSHIFT页面上尝试实现的算法。我只需要返回一个从0到31的随机数,所以对一个10位数字进行除法需要一段时间,而且似乎有点过头了。如果有人能帮我优化或指出错误,我将不胜感激
编辑:上面的子例程返回随机数,然后我基本上将它除以31(这里没有给出代码),并将余数作为从0到31的“随机”数 ARM指令,因此使用单独的左移位指令是一种浪费。显然
请注意,如果您的例程是您实际调用的函数,而不仅仅是来自循环的内联代码段,那么它就不符合标准ABI。如果唯一的调用方也是由您在asm中编写的,那么这很好。若您可以将4个寄存器专用于循环中的PRNG状态,那个么您就不需要传递指针或加载/存储
一如既往,这通常是一个很好的起点:
// we need a loop to see how many mov instructions are actually needed when keeping state in regs
// Otherwise we just get loads/stores
uint32_t xorshift_loop(uint32_t *output, uint32_t x, uint32_t y, uint32_t z, uint32_t w) {
for(int i=0 ; i<1000 ; ++i) {
uint32_t t = x;
t ^= t << 11;
t ^= t >> 8;
x = y; y = z; z = w;
w ^= w >> 19;
w ^= t;
*(++output) = w;
}
return w;
}
请注意XOR是如何重新排序的,因此前几条指令是独立dep链的一部分。这将有助于ARM内核的超标量排序,或者如果移位操作数的eor
延迟大于1。它还选择做w^=t;w^=t>>8
而不是t^=t>>8;w^=t代码>,但如果有任何特殊的优势,请拨打IDK
两次展开将删除所有mov
指令,使每个迭代只执行四条eor
指令,每个结果的输入都会发生移位。它看起来像带有-funroll循环的gcc,以8展开,因此代码很难理解
为了这么快的东西
它在AArch64上编译成短代码,在32位ARM上仍然编译成短/高效的代码。不过,代码远不止xorshift。请参阅上面的“我的godbolt编译器浏览器”链接您的分区错误;它应该是“除以32”以得到31的可能余数。但“模32”只是“和31”,保留较低的5位。啊,使用和31可以大大缩短时间。非常感谢。谢谢你的深入回答!在线移位/旋转使我的代码更加清晰。回答得很好。
## 32bit ARM gcc 4.8 -O3 -fverbose-asm
## The @comments are from -fverbose-asm, which is more helpful than usual here
.L4:
eor r6, r1, r1, lsl #11 @, t, x, x,
eor r5, r4, r4, lsr #19 @, w, w, w,
eors r5, r5, r6 @, t, w, t
mov r1, r2 @ x, y
eor r5, r5, r6, lsr #8 @, w, t, t,
str r5, [r0, #4]! @ w, MEM[base: _42, offset: 4B] // this is a post-increment store
cmp r0, r7 @ ivtmp.20, D.4237
mov r2, r3 @ y, z
mov r3, r4 @ z, w
mov r4, r5 @ w, w
bne .L4 @,