首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >手臂装配的PRNG?

手臂装配的PRNG?
EN

Stack Overflow用户
提问于 2016-03-30 06:57:51
回答 1查看 472关注 0票数 1

我在为ARM大会执行PRNG时遇到了问题。我尝试了一些算法,在工作的同时,在最初的几次随机数迭代之后,最终花费了很长的时间,这可能是因为除法(模)步骤对大数需要很长的时间。我试着得到0到31之间的随机数。我在下面做了一些粗略的工作,用字母代替了特定的寄存器。

开始:

代码语言:javascript
复制
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

这就是我试图从维基百科的XORSHIFT页面实现的算法。我只需要这个来返回一个从0到31的随机数,所以在一个10位数的数字上实现除法需要一段时间,而且看起来很过火。如果有人能帮我优化或者指出一个错误,我会很感激的。

编辑:上面的子例程返回随机数,然后我基本上把它除以31 (这里没有给出代码),并把剩余的作为我的“随机”数从0到31。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-30 09:47:20

ARM指令可以动态地移动甚至旋转它们的输入,所以使用分开的左移位指令是一种浪费.显然是在拇指模式下,只有32位的拇指指令才能使用桶形移位器。

请注意,如果您的例程是实际调用的函数,而不仅仅是循环中的内联片段,那么它就不遵循标准的ABI。如果唯一的调用者也是由您在asm中编写的,这是很好的。如果您可以将4个寄存器专用于循环中的PRNG状态,则不需要传递指针或加载/存储。

和往常一样,编译器输出通常是一个很好的起点:

代码语言:javascript
复制
// 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;
}

内环是:

代码语言:javascript
复制
## 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       @,

注意XOR是如何被重新排序的,所以第一对指令是分开的dep链的一部分。这将有助于超标量有序ARM核,或者如果移动操作数的eor的延迟大于1,它也选择做w^=t; w^= t>>8而不是t^= t>>8; w^=t;,但是如果有什么特别的优势的话。

展开两次就可以去掉所有的mov指令,让每次迭代只执行四个eor指令,每个结果都有移位的输入。看起来gcc用-funroll-loops 8展开,所以代码很难理解。

很明显质量很好为了这么快的东西。

它在AArch64上编译成短代码,在32位ARM上仍然是短/高效的代码。但是,不仅仅是xorshift,还有更多的代码。请参阅上面的“我的霹雳编译器资源管理器”链接。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36301753

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档