在x86_64中,我知道mul和div的代码支持128个整数,方法是将rax中的低64位和rdx寄存器的高位放在一起。我在intel intrinsics指南中寻找某种内在的功能,我找不到一个。我正在写一个大字库,字大小为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,那就太好了。
答案 0 :(得分:2)
gcc有__int128
和__uint128
种类型。
算术应该使用正确的汇编指令;我过去曾使用它们来获得产品的高64位,尽管我从来没有将它用于分割。如果它没有使用正确的,请提交错误报告/功能请求。
答案 1 :(得分:1)
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是否计划支持这些,因为您可以通过mul
(取决于您的编译选项)或直接通过内联汇编间接获得mulx
和__int128
。
__int128
正常工作,直到您需要更大的类型和128位进位。然后,您需要adc
,adcx
或adox
,这些内在函数更是一个问题。英特尔的文档与MSVC不同意,编译器似乎还没有使用这些内在函数生成adox
。请参阅此问题:_addcarry_u64 and _addcarryx_u64 with MSVC and ICC。
内联汇编可能是GCC(甚至可能是ICC)的最佳解决方案。