【问题标题】:Intrinsics for 128 multiplication and division128乘法和除法的内在函数
【发布时间】:2015-12-09 00:49:42
【问题描述】:

在 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,那就太好了。

【问题讨论】:

  • 由于 asm 已经是特定于编译器的,您不妨只使用 __int128 类型,它会自动执行您想要的操作。
  • 看看_mulx_u64。看起来非常适合您使用,尽管它会生成仅在较新的 x86 处理器上存在的 mulx 指令。
  • 在特定于架构的内在函数和特定于架构的程序集之间进行选择;后者有更好的文档、更好的支持、更广泛的理解和更易于维护(无需猜测编译器实际上做了什么)。

标签: c gcc inline-assembly intrinsics 128-bit


【解决方案1】:

gcc 有 __int128__uint128 类型。

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

【讨论】:

  • 我在-03上构建代码时反编译了代码。我很惊讶 gcc 在使用 128 位除法时调用的是一个函数而不是内联一个函数。只是看起来有点慢。
  • @chasep255 GCC 不使用 DIV/IDIV 的“扩展”形式,因为它不符合标准。这对于 64 位 x86 目标上的 128 位红利和 32 位 x86 目标上的 64 位红利都是如此。问题是,在标准规定结果应该被截断的情况下,DIV 会导致除法溢出异常。例如(unsigned long long) (((unsigned _int128) 1 &lt;&lt; 64) / 1) 应该计算为 0,但如果使用 DIV 计算会导致除法溢出异常。
【解决方案2】:

Last I looked into it the intrinsic were in a state of flux。在这种情况下,内部函数的主要原因似乎是由于 64 位模式下的 MSVC 不允许内联汇编。

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

__int128 工作正常,直到您需要更大的类型和 128 位进位。然后你需要adcadcxadox,这些对内在函数来说更是一个问题。英特尔的文档不同意 MSVC,编译器似乎还没有使用这些内在函数生成 adox。看到这个问题:_addcarry_u64 and _addcarryx_u64 with MSVC and ICC

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

【讨论】:

    猜你喜欢
    • 2012-01-17
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2018-07-18
    • 2012-03-15
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    相关资源
    最近更新 更多