MSVC为某些乘法和除法生成奇/慢二进制

时间:2011-04-06 15:52:15

标签: c++ visual-c++ assembly

我使用的是MSVC 2010 SP1,我有以下几行C ++代码:

int32_t c = (int64_t(a)*int64_t(b))>>2;

ab不是常量时,MSVC会正确生成32位imulshrd指令。但是当ab是常量时,它会生成对_allmull的调用,而不是imul指令。这有什么理由吗?如何强制/引导它始终生成良好的代码?令我烦恼的是,当它有更多的编译时间信息时,它会产生更糟糕的代码。我发现_allmull函数执行64位乘法,但我认为在这种情况下不需要它。

我也注意到,对于一行int32_t c = (int64_t(a)*int64_t(b))/4;,它甚至会为除法生成_alldiv 4。

修改 这似乎是一个编译器错误。我填了bug report

3 个答案:

答案 0 :(得分:2)

部分相关:如果您想确保利用执行32x32 => 64位乘法的imul功能,您可以使用Int32x32To64“假API”(实际上是一个宏):

  

将两个带符号的32位整数相乘,返回带符号的64位整数结果。该功能在32位Windows上运行最佳。

     

此函数通过最佳内联代码在所有平台上实现:单个乘法指令,返回64位结果。

顺便问一下,您是否启用了优化?如果在启用优化的情况下编译器无法自行解决问题,我会感到非常困惑。


修改

有趣的是,在Int32x32To64中寻找winnt.h,您会发现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))

因此,即使Platform SDK信任编译器做正确的事情,它也一定会产生imul


再次修改

如果您需要确保获得imul,则可以使用__emul compiler intrinsic

答案 1 :(得分:1)

如果我在没有优化的情况下运行编译器,我会看到allmul,但是使用/ Ox,我看到了一些移位组合,并且它们依赖于常量部分的值。

我认为您需要提供一些特定的代码,以及您使用过的编译器选项。

答案 2 :(得分:0)

您是否尝试过解决方法:

int32_t c = (int64_t(int32_t(a))*int64_t(int32_t(b)))>>2;