3

在 x86_64 中,我知道 mul 和 div opp 代码支持 128 个整数,方法是将低 64 位放在 rax 中,将高位放在 rdx 寄存器中。我在 intel 内在函数指南中寻找某种内在函数来执行此操作,但我找不到。我正在编写一个字长为 64 位的大数字库。现在我正在用这样的一个词进行除法。

int ubi_div_i64(ubigint_t* a, ubi_i64_t b, ubi_i64_t* rem)
{
    if(b == 0)
        return UBI_MATH_ERR;

    ubi_i64_t r = 0;

    for(size_t i = a->used; i-- > 0;)
    {

        ubi_i64_t out;
        __asm__("\t"
                "div %[d] \n\t"
                : "=a"(out), "=d"(r)
                : "a"(a->data[i]), "d"(r), [d]"r"(b)
                : "cc");
        a->data[i] = out;


        //ubi_i128_t top = (r << 64) + a->data[i];
        //r = top % b;
        //a->data[i] = top / b;
    }
    if(rem)
        *rem = r;

    return ubi_strip_leading_zeros(a);
}

如果我可以在 x86intrinsics.h 标头中使用某些东西而不是内联 asm,那就太好了。

4

2 回答 2

2

gcc 有__int128__uint128类型。

当它们存在时,应该使用正确的汇编指令进行算术运算;我过去曾使用它们来获取产品的高 64 位,尽管我从未将其用于除法。如果没有使用正确的,请酌情提交错误报告/功能请求。

于 2015-09-12T15:59:10.370 回答
1

最后我调查了它的内在是在一个不断变化的状态。在这种情况下,内部函数的主要原因似乎是由于 64 位模式下的 MSVC 不允许内联汇编。

使用 MSVC(我认为是 ICC),您可以使用_umul128formul_mulx_u64for mulx。这些在 GCC 中不起作用,至少在 GCC 4.9 中不起作用(_umul128比 GCC 4.9 早得多)。我不知道 GCC 是否计划支持这些,因为您可以mul间接mulx通过__int128(取决于您的编译选项)或直接通过内联汇编获得。

__int128工作正常,直到您需要更大的类型和 128 位进位。然后你需要adc, adcx, oradox并且这些是内在函数的更多问题。英特尔的文档不同意 MSVC 并且编译器似乎adox还没有使用这些内在函数生成。请参阅此问题:_addcarry_u64 和 _addcarryx_u64 with MSVC and ICC

内联汇编可能是 GCC(甚至可能是 ICC)的最佳解决方案。

于 2015-09-28T08:32:48.273 回答