我使用的是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;
,它甚至会为除法生成_alldiv 4。
修改 这似乎是一个编译器错误。我填了bug report。
答案 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;