C++ 为什么clang和GCC不使用xchg来实现std::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-与寄存器交换寄存器/内存 交换目标第一个操作数和源第二个操作数的内容。操作数可以是两个通用寄存器,也可以是一个寄存器和一个内存位置 那么,编译器不可能在这里使用xchg有什么特别的原因吗?我也尝试过其他示例,例如交换指针、交换三个操作数、交换除char以外的类型,但我从未在编译输出中获得xchg。为什么 那么,编译器不可能在这里使用xchg有什么特别的原因吗 因为mov比xchg快,编译器优化了速度 见: 那么,编译器不可能在这里使用xchg有什么特别的原因吗 因为mov比xchg快,编译器优化了速度 见: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-与
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的另一个缺点。