Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.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
C++ 为什么clang和GCC不使用xchg来实现std::swap?_C++_Compilation_X86_Swap - Fatal编程技术网

C++ 为什么clang和GCC不使用xchg来实现std::swap?

C++ 为什么clang和GCC不使用xchg来实现std::swap?,c++,compilation,x86,swap,C++,Compilation,X86,Swap,我有以下代码: char swapchar reg,char*mem{ 标准:swapreg,*mem; 返回注册表; } 我希望这可以归结为: swapchar,char*: xchg dil,字节ptr[rsi] mov al,dil ret 但它实际上编译为-O3-march=haswell-std=c++20: swapchar,char*: mov al,字节ptr[rsi] mov字节ptr[rsi],dil ret 看 根据xchg的文档,第一种形式应该是完全可能的: XCHG-与

我有以下代码:

char swapchar reg,char*mem{ 标准:swapreg,*mem; 返回注册表; } 我希望这可以归结为:

swapchar,char*: xchg dil,字节ptr[rsi] mov al,dil ret 但它实际上编译为-O3-march=haswell-std=c++20:

swapchar,char*: mov al,字节ptr[rsi] mov字节ptr[rsi],dil ret 看

根据xchg的文档,第一种形式应该是完全可能的:

XCHG-与寄存器交换寄存器/内存 交换目标第一个操作数和源第二个操作数的内容。操作数可以是两个通用寄存器,也可以是一个寄存器和一个内存位置

那么,编译器不可能在这里使用xchg有什么特别的原因吗?我也尝试过其他示例,例如交换指针、交换三个操作数、交换除char以外的类型,但我从未在编译输出中获得xchg。为什么

那么,编译器不可能在这里使用xchg有什么特别的原因吗

因为mov比xchg快,编译器优化了速度

见:

那么,编译器不可能在这里使用xchg有什么特别的原因吗

因为mov比xchg快,编译器优化了速度

见:


TL:DR:因为编译器优化的是速度,而不是听起来相似的名称。还有很多其他可怕的方法,他们也可以实现它,但选择不

带有mem的xchg在386和更高版本上有一个隐式锁前缀,所以速度非常慢。除非您需要原子交换,或者完全优化代码大小而不考虑性能,否则您总是希望避免这种情况,如果您确实希望结果与原始值位于同一寄存器中。有时会在朴素的性能中看到不经意的手写气泡,作为交换2个内存位置的一部分

可能clang-Oz会那么疯狂,IDK,但希望在这种情况下不会,因为xchg方式的代码量更大,需要在两条指令上都使用REX前缀才能访问DIL,而2-mov方式是2字节和3字节指令。clang-Oz做了一些事情,比如push 1/pop rax而不是mov eax,1以节省2字节的代码大小

GCC-Os不会将xchg用于不需要原子的交换,因为-Os仍然关心速度

另外,IDK为什么您认为依赖xchg+的mov比两条可以并行运行的独立mov指令更快或更好。存储缓冲区确保加载后存储的顺序正确,而不管哪个uop首先发现其执行端口空闲

请参阅中的和其他链接

说真的,我看不出有什么合理的理由可以让编译器使用xchg,特别是考虑到调用约定在RAX中没有传递arg,所以仍然需要2条指令。即使对于寄存器,英特尔CPU上的xchg reg,reg也是3个UOP,它们是微码UOP,不能从mov消除中获益。一些AMD CPU具有2-uop xchg reg,reg


我也猜你看到的是铿锵的输出;通过使用movzx eax,即使返回值只是低字节,字节ptr[rsi]也会加载。零扩展负载比合并到RAX的旧值便宜。因此,这是xchg的另一个缺点。

带有mem的xchg在386和更高版本上有一个隐式锁前缀,所以速度非常慢。除非您需要原子交换,或者完全优化代码大小而不考虑性能,否则您总是希望避免这种情况,如果您确实希望结果与原始值位于同一寄存器中。有时会在朴素的性能中看到不经意的手写气泡,作为交换2个内存位置的一部分

可能clang-Oz会那么疯狂,IDK,但希望在这种情况下不会,因为xchg方式的代码量更大,需要在两条指令上都使用REX前缀才能访问DIL,而2-mov方式是2字节和3字节指令。clang-Oz做了一些事情,比如push 1/pop rax而不是mov eax,1以节省2字节的代码大小

GCC-Os不会将xchg用于不需要原子的交换,因为-Os仍然关心速度

另外,IDK为什么您认为依赖xchg+的mov比两条可以并行运行的独立mov指令更快或更好。存储缓冲区确保加载后存储的顺序正确,而不管哪个uop首先发现其执行端口空闲

请参阅中的和其他链接

说真的,我看不出有什么合理的理由让你认为编译器可能想要使用xchg,特别是考虑到调用约定在R中没有传递arg 所以你仍然需要2个说明。即使对于寄存器,英特尔CPU上的xchg reg,reg也是3个UOP,它们是微码UOP,不能从mov消除中获益。一些AMD CPU具有2-uop xchg reg,reg

我也猜你看到的是铿锵的输出;通过使用movzx eax,即使返回值只是低字节,字节ptr[rsi]也会加载。零扩展负载比合并到RAX的旧值便宜。这是xchg的另一个缺点