使用单个aarch64指令获取余数?

时间:2016-02-11 22:37:17

标签: assembly arm arm64

我正在为ARM8编写一些汇编代码(aarch64)。我想进行划分并使用获得的余数进行进一步计算。在我使用的x86中 'div',我知道我的余数保存在 RDX 中。我的问题是 - 是否有与aarch64指令集相同的内容?我知道'udiv'和'sdiv'做无符号和签名的分歧,并得到了商数。是否有一条指令会给我余数? (我想在c中使用%modulo运算符)。我知道我可以使用代数来获取它,只是想确认我没有错过更简单的方法。

2 个答案:

答案 0 :(得分:4)

除了可以优化到and的恒定二次幂除数之外,没有指令可以计算除法的余数。但是,你可以在两个方面做得非常整洁:

// input: x0=dividend, x1=divisor
udiv x2, x0, x1
msub x3, x2, x1, x0
// result: x2=quotient, x3=remainder

答案 1 :(得分:2)

计算余数不是一条指令

Clang C 编译器为模计算生成了以下代码:

udiv    x10, x0, x9
msub    x10, x10, x9, x0

好消息,这并不慢!

虽然 x86 在一条指令中完成这些,但这并没有使它更快。

在 Apple M-1 上,上述指令对的执行时间与单个步骤大致相同。这可能是由于 instruction macro-fusion 将多个指令解码为单个 µ-op。这也可能是由于多个 execution units 中的并行性。可能是在一个 EU 中完成的,其中除法计算的余数被缓存并立即返回。

无论采用何种实现方式,它似乎都与英特尔的单指令形式一样快。

仅限部门

时间:

$ time ./a.out 12345678901
Total: 301123495054
real    0m10.036s
user    0m9.668s
sys 0m0.031s

生成的指令:

udiv    x10, x0, x9

仅剩余部分

时间:

$ time ./a.out 12345678901
Total: 8612082846779832640
real    0m10.190s
user    0m9.768s
sys 0m0.070s

生成的指令:

udiv    x10, x0, x9
msub    x10, x10, x9, x0

除法和余数

时间:

$ time ./a.out 12345678901
Total: 8612083123211969892
real    0m10.103s
user    0m9.752s
sys 0m0.019s

生成的指令:

udiv    x10, x0, x9
msub    x11, x10, x9, x0

基准代码

以下 C 代码可以在注释掉 q = n / dr = n % d 的情况下运行:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    unsigned long long n, d, q=1, r=1, total=0;

    n = strtoull(argv[1], NULL, 10);
    total = 0;
    for (d=1 ; d<=n ; d++) {
        q = n / d;
        r = n % d;
        total += q + r;
    }
    printf("Total: %llu", total);
    return 0;
}