Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
VS 2008/2010中的x86 MUL指令 Visual Studio或Visual C++的现代(2008/2010)咒语在编译的代码中会产生x86 MUL指令(无符号乘法)吗?我似乎找不到或设计出一个例子,说明它们出现在编译代码中,即使在使用无符号类型时也是如此_C++_Visual Studio_Compiler Construction_Assembly_X86 - Fatal编程技术网

VS 2008/2010中的x86 MUL指令 Visual Studio或Visual C++的现代(2008/2010)咒语在编译的代码中会产生x86 MUL指令(无符号乘法)吗?我似乎找不到或设计出一个例子,说明它们出现在编译代码中,即使在使用无符号类型时也是如此

VS 2008/2010中的x86 MUL指令 Visual Studio或Visual C++的现代(2008/2010)咒语在编译的代码中会产生x86 MUL指令(无符号乘法)吗?我似乎找不到或设计出一个例子,说明它们出现在编译代码中,即使在使用无符号类型时也是如此,c++,visual-studio,compiler-construction,assembly,x86,C++,Visual Studio,Compiler Construction,Assembly,X86,如果VS不使用MUL编译,有什么理由吗?我的直觉告诉我,编译器任意选择了IMUL(或者两者中速度更快的一个),因为无论它使用无符号MUL还是有符号IMUL,位都是相同的。任何32位整数乘法将是跨越两个寄存器的64位,EDX:EAX。溢出进入EDX,这基本上被忽略,因为我们只关心EAX中的32位结果。根据需要,使用IMUL将符号扩展到EDX,但我们不在乎,因为我们只对32位结果感兴趣。根据,IMUL指令具有较低的延迟和较高的吞吐量(如果我正确读取表的话)。也许VS只是简单地使用了更快的指令(假设I

如果VS不使用MUL编译,有什么理由吗?

我的直觉告诉我,编译器任意选择了
IMUL
(或者两者中速度更快的一个),因为无论它使用无符号
MUL
还是有符号
IMUL
,位都是相同的。任何32位整数乘法将是跨越两个寄存器的64位,
EDX:EAX
。溢出进入
EDX
,这基本上被忽略,因为我们只关心
EAX
中的32位结果。根据需要,使用
IMUL
将符号扩展到
EDX
,但我们不在乎,因为我们只对32位结果感兴趣。

根据,
IMUL
指令具有较低的延迟和较高的吞吐量(如果我正确读取表的话)。也许VS只是简单地使用了更快的指令(假设
IMUL
MUL
总是产生相同的输出)

我手头没有VisualStudio,所以我尝试用GCC获取其他东西。我也总是得到一些变化的
IMUL

这:

unsigned int func(unsigned int a, unsigned int b)
{ 
    return a * b;
}
组装到此(使用-O2):

imul
(有符号)和
mul
(无符号)都有一个单操作数形式,它的edx:eax=eax*src。i、 e.32x32b=>64b全乘(或64x64b=>128b)

表单,386添加了一个
imulr32,r/m32
表单,这两个表单都只计算结果的下半部分。(根据,另请参见)

当两个32位值相乘时,无论考虑到签名或未签名的值,结果的最小32位都是相同的。换句话说,只有在查看结果的“上”半部分时,有符号乘法和无符号乘法之间的差异才会变得明显,其中一个操作数

imul
/
mul
放在
edx
中,而两个或三个操作数
imul
不放在任何地方。因此,
imul
的多操作数形式可用于有符号和无符号值,英特尔也无需添加新形式的
mul
。(它们可以使多操作数
mul
成为
imul
的同义词,但这会使反汇编输出与源不匹配。)

在C语言中,算术运算的结果与操作数的类型相同(对于窄整数类型,在整数提升之后)。如果将两个
int
相乘,则得到的是
int
,而不是
long
:不保留“上半部分”。因此,C编译器只需要
imul
提供的内容,并且由于
imul
mul
更易于使用,C编译器使用
imul
来避免需要
mov
指令将数据输入/输出
eax

作为第二步,由于C编译器大量使用imul的多操作数形式,Intel和AMD投入了大量精力使其尽可能快。它只写一个输出寄存器,而不是
e/rdx:e/rax
,因此CPU可以比单操作数形式更容易地对其进行优化。这使得imul更具吸引力


当实现大数算术时,
mul
/
imul
的单操作数形式很有用。在C语言中,在32位模式下,您应该通过将
无符号long-long
值相乘来获得一些
mul
调用。但是,根据编译器和操作系统的不同,这些
mul
操作码可能隐藏在某些专用函数中,因此您不一定会看到它们。在64位模式下,
long-long
只有64位,而不是128位,编译器只需使用
imul

x86上有三种不同类型的乘法指令。第一个是
MUL-reg
,它将
EAX
与reg进行无符号相乘,并将(64位)结果放入
EDX:EAX
。第二个是
IMUL reg
,它对有符号乘法也有同样的作用。第三种类型是
IMUL reg1,reg2
(将reg1与reg2相乘并将32位结果存储到reg1)或
IMUL reg1,reg2,imm
(将reg2与imm相乘并将32位结果存储到reg1)

由于在C语言中,两个32位值的乘法产生32位结果,编译器通常使用第三种类型(有符号性并不重要,低32位在有符号和无符号的32x32乘法之间一致)。如果您实际使用完整的64位结果,VC++将生成
MUL
/
IMUL
的“长乘法”版本,例如:

unsigned long long prod(unsigned int a, unsigned int b)
{
  return (unsigned long long) a * b;
}

IMUL的两个操作数(和三个操作数)版本比一个操作数版本快,只是因为它们不能生成完整的64位结果。宽乘数大而慢;如果需要的话,构建更小的乘法器和使用微码合成长乘法器要容易得多。此外,MUL/IMUL写入两个寄存器,通常通过在内部将其分解为多条指令来解决这一问题——指令重新排序硬件更容易跟踪两条相互依赖的指令,每条指令写入一个寄存器(大多数x86指令在内部看起来都是这样)而不是跟踪一条写两条指令的指令。

在我看了这个问题之后,我在分割时在生成的代码中发现了MULQ

完整的代码将一个大的二进制数转换成10亿的块,以便可以轻松地将其转换为字符串

C++代码:

for_each(TempVec.rbegin(), TempVec.rend(), [&](Short & Num){
    Remainder <<= 32;
    Remainder += Num;
    Num = Remainder / 1000000000;
    Remainder %= 1000000000;//equivalent to Remainder %= DecimalConvert
});
注意MUL指令向下5行。 这个生成的代码非常不直观,我知道,事实上它看起来与编译后的代码完全不同,但是DIV非常慢,对于一个32位的DIV来说是25个周期,根据这个例子是75个周期
for_each(TempVec.rbegin(), TempVec.rend(), [&](Short & Num){
    Remainder <<= 32;
    Remainder += Num;
    Num = Remainder / 1000000000;
    Remainder %= 1000000000;//equivalent to Remainder %= DecimalConvert
});
00007FF7715B18E8  lea         r9,[rsi-4]  
00007FF7715B18EC  mov         r13,12E0BE826D694B2Fh  
00007FF7715B18F6  nop         word ptr [rax+rax] 
00007FF7715B1900  shl         r8,20h  
00007FF7715B1904  mov         eax,dword ptr [r9]  
00007FF7715B1907  add         r8,rax  
00007FF7715B190A  mov         rax,r13  
00007FF7715B190D  mul         rax,r8  
00007FF7715B1910  mov         rcx,r8  
00007FF7715B1913  sub         rcx,rdx  
00007FF7715B1916  shr         rcx,1  
00007FF7715B1919  add         rcx,rdx  
00007FF7715B191C  shr         rcx,1Dh  
00007FF7715B1920  imul        rax,rcx,3B9ACA00h  
00007FF7715B1927  sub         r8,rax  
00007FF7715B192A  mov         dword ptr [r9],ecx  
00007FF7715B192D  lea         r9,[r9-4]  
00007FF7715B1931  lea         rax,[r9+4]  
00007FF7715B1935  cmp         rax,r14  
00007FF7715B1938  jne         NumToString+0D0h (07FF7715B1900h)