MSVC 为某些乘法和除法生成奇怪/慢速二进制
MSVC generates strange/slow binary for some multiplications and divisions
我使用 MSVC 2010 SP1,我有以下C++行代码:
int32_t c = (int64_t(a)*int64_t(b))>>2;
当a
和b
不是常量时,MSVC 会正确生成 32 位imul
并shrd
指令。但是当a
或b
是常量时,它会生成对_allmull
的调用,而不是imul
指令。这有什么原因吗?如何强制/引导它始终生成良好的代码?困扰我的是,为什么当它有更多的编译时信息时,它会生成更糟糕的代码。我发现_allmull
函数执行 64 位乘法,但我认为在这种情况下不需要它。
我还注意到,对于int32_t c = (int64_t(a)*int64_t(b))/4;
行,它甚至会生成除以 4 的_alldiv。
编辑:这似乎是编译器错误。我已经填写了错误报告。
部分相关:如果你想确保利用执行 32x32=>64 位乘法的imul
功能,你可以使用Int32x32To64
"假 API"(实际上是一个宏):
将两个有符号 32 位整数相乘,返回有符号 64 位整数结果。该函数在 32 位 Windows 上以最佳方式执行。
此函数在所有平台上通过最佳内联代码实现:返回 64 位结果的单个乘法指令。
顺便问一下,您是否启用了优化?如果在启用优化的情况下,编译器无法自行弄清楚,我会感到非常困惑。
<小时 />编辑 :
有趣的是,在 winnt.h
中寻找Int32x32To64
,您会发现 x86:
//
// The x86 C compiler understands inline assembler. Therefore, inline functions
// that employ inline assembler are used for shifts of 0..31. The multiplies
// rely on the compiler recognizing the cast of the multiplicand to int64 to
// generate the optimal code inline.
//
#define Int32x32To64( a, b ) (LONGLONG)((LONGLONG)(LONG)(a) * (LONG)(b))
#define UInt32x32To64( a, b ) (ULONGLONG)((ULONGLONG)(DWORD)(a) * (DWORD)(b))
因此,如果即使平台SDK也信任编译器做正确的事情,它肯定会产生imul
。
再次编辑:
如果你需要确保得到一个imul
,你可以使用__emul
编译器内部函数。
如果我在没有优化的情况下运行编译器,我会看到 allmul,但是使用/Ox,我会看到移位和添加的组合,这取决于常量部分的值。
我认为您需要提供特定的代码以及您使用的编译器选项。
尝试过解决方法:
int32_t c = (int64_t(int32_t(a))*int64_t(int32_t(b)))>>2;
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 有根的二进制搜索树.保留与其父级的链接
- 多态二进制函数
- 正在读取二进制文件(is_open)
- visual在c++中将十进制数转换为二进制数
- C++十进制到二进制,如何转换
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- 二进制搜索树叶数问题
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- 为什么二进制搜索在我的测试中不起作用
- 重载==不适用于二进制树
- 正在尝试重载二进制搜索树分配运算符
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 在除法中不需要四舍五入
- 带有数组键C++的二进制映射
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 二进制数之和(使用C样式字符串)
- MSVC 为某些乘法和除法生成奇怪/慢速二进制