[英]What is the use of this asm block using x86 DIV in c++?
有人可以帮助我了解在性能方面使用asm块进行unsigned long long
乘法的好处。 它与竞争性编程优化有关。 我猜想它使乘法运算更快,但是我实际上无法理解代码。
const int md = 998244353;
inline int mul(int a, int b)
{
#if !defined(_WIN32) || defined(_WIN64)
return (int) ((long long) a * b % md);
#endif
unsigned long long x = (long long) a * b;
unsigned xh = (unsigned) (x >> 32), xl = (unsigned) x, d, m;
asm(
"divl %4; \n\t"
: "=a" (d), "=d" (m)
: "d" (xh), "a" (xl), "r" (md)
);
return m;
}
此代码实际上是32位(其中,所以编译器使用实际分割64×64 => 128乘法是不可用的加速,但在64位,其中编译器确实使用乘法逆完全避免慢硬件分割严重丧失。 为什么GCC在实现整数除法时使用乘以奇数的乘法?
另外,如果在内联和常量传播之后,任何一个输入都不是编译时常量,则它实际上应该使用__builtin_constant_p
仅使用嵌入式asm。
但是无论如何, x86的div
指令执行EDX:EAX / (src)
=>商(EAX)和除数(EDX)。 请参阅何时以及为什么我们要对extend进行签名并在mul / div中使用cdq?
"a"
和"d"
约束分别要求EAX和EDX中64位乘积的低半和高半作为输入。
const int md = 998244353;
int mul(int a, int b)
{
#ifdef __x86_64__ // FIXME: just use the asm if defined(i386) to exclude all others
return (int) ((long long) a * b % md);
#else
if(__builtin_constant_p(a) && __builtin_constant_p(b))
return (int) ((long long) a * b % md);
// clang's builtin_constant_p is evaled before inlining, derp
unsigned long long x = (long long) a * b;
unsigned xh = (unsigned) (x >> 32), xl = (unsigned) x, d, m;
asm(
"divl %4; \n\t"
: "=a" (d), "=d" (m)
: "d" (xh), "a" (xl), "r" (md)
);
return m;
#endif
}
int main() {
return mul(1,2);
}
使用gcc8.2 -O3 -m32
编译如下:
mul(int, int):
mov eax, DWORD PTR [esp+8]
mov ecx, 998244353
imul DWORD PTR [esp+4] # one-operand imul does EDX:EAX = EAX * src
divl ecx; # EDX:EAX / ecx => EAX and EDX
mov eax, edx # return the remainder
ret
main:
mov eax, 2 # builtin_constant_p used the pure C, allowing constant-propagation
ret
注意div
是无符号除法,因此它与C不匹配。C正在执行有符号乘法和有符号除法。 这可能应该使用idiv
,或将输入转换为无符号。 或者,也许由于某些奇怪的原因,他们确实确实想要带有负输入的怪异结果。
那么,为什么没有内联汇编程序,编译器为什么不能自己发出此消息? 因为如果商溢出目标寄存器(al / ax / eax / rax),它将以#DE(除法异常)错误而不是像其他所有整数指令一样默默地截断。
仅当您知道除数足够大以进行可能的除数时,64位/ 32位=> 32位除法才是安全的。 (但是即使是,gcc仍然不知道寻找这种优化。例如, a * 7ULL / 9
则如果使用单个mul
和div
来完成,则可能不会导致#DE;如果a
是32位类型的话。但是gcc仍会发出对libgcc helper函数的调用。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.