【发布时间】:2017-09-03 02:13:57
【问题描述】:
我在GodBolt上玩过,看到x86-64 gcc(6.3)编译了以下代码:
typedef __int128_t int128_t;
typedef __uint128_t uint128_t;
uint128_t mul_to_128(uint64_t x, uint64_t y) {
return uint128_t(x)*uint128_t(y);
}
uint128_t mul(uint128_t x, uint128_t y) {
return x*y;
}
uint128_t div(uint128_t x, uint128_t y) {
return x/y;
}
我得到了:
mul_to_128(unsigned long, unsigned long):
mov rax, rdi
mul rsi
ret
mul(unsigned __int128, unsigned __int128):
imul rsi, rdx
mov rax, rdi
imul rcx, rdi
mul rdx
add rcx, rsi
add rdx, rcx
ret
div(unsigned __int128, unsigned __int128):
sub rsp, 8
call __udivti3 //what is this???
add rsp, 8
ret
3 个问题:
- 第一个函数(将
64-bituint 转换为128-bit然后将它们相乘)是 比 2 128 位 uints(第二个函数)的乘法简单得多。基本上,只要 1 乘法。如果将 2 个最大值乘以 64 位 uint,它 肯定会溢出 64 位寄存器...它是如何产生的 128 位结果只需 1 次 64 位 - 64 位乘法??? - 我无法很好地读取第二个结果...我的猜测是将 64 位数字分解为 2 个 32 位数字(例如,
hi更高的 4 个字节 和lo作为低 4 个字节),并像这样组装结果(hi1*hi2)<<64 + (hi1*lo2)<<32 + (hi2*lo1)<<32+(lo1*lo2)。显然 我错了......因为它只使用 3 个乘法(其中 2 个 甚至是imul...有符号乘法???为什么???)。谁能告诉我 gcc 在想什么?它是最优的吗? - 甚至无法理解除法的组装...推栈->调用名为
__udivti3的东西然后弹出栈...是__udivti3的东西 大?(比如查表?) gcc 在调用之前会尝试推送什么内容?
【问题讨论】:
-
64 位 x86 乘法是 64 位、64 位 -> 128 位操作。
-
如果您要查看编译器的汇编语言输出,您需要找到它的参考,因为其中有太多内容,仅阅读输出并不明显。
-
我建议你在指令集参考中查找
mul,然后一切就清楚了。
标签: c++ gcc assembly x86-64 compiler-optimization