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

2023-11-29

我有以下代码:

char swap(char reg, char* mem) {
    std::swap(reg, *mem);
    return reg;
}

我预计这会编译为:

swap(char, char*):
    xchg    dil, byte ptr [rsi]
    mov     al, dil
    ret

但它实际编译的结果是(在-O3 -march=haswell -std=c++20):

swap(char, char*):
    mov     al, byte ptr [rsi]
    mov     byte ptr [rsi], dil
    ret

See 这里有现场演示.

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

XCHG - 交换寄存器/内存与寄存器

交换目标(第一个)和源(第二个)操作数的内容。操作数可以是两个通用寄存器或一个寄存器和一个内存位置。

那么是否有任何特殊原因导致编译器无法使用xchg这里?我也尝试过其他示例,例如交换指针、交换三个操作数、交换除char但我从来没有得到xchg在编译输出中。怎么会?


TL:DR:因为编译器针对速度进行优化,而不是针对听起来相似的名称。他们也可以采用许多其他可怕的方式来实施它,但他们选择不这样做。

xchg 与 mem 有一个隐含的lock前缀(在 386 及更高版本上),所以速度非常慢。你总是想避免它,除非你need原子交换,或者正在完全优化代码大小而不关心at all为了性能,如果您确实希望结果与原始值位于同一寄存器中。有时表现为天真(表现不经意)或代码高尔夫球手写的冒泡排序作为交换 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仍然关心some关于速度。


另外,我不知道你为什么认为 xchg + dependent mov 会比两个独立的更快或更好的选择mov可以并行运行的指令。 (存储缓冲区确保加载后存储的顺序正确,无论哪个 uop 首先发现其执行端口空闲)。

See https://agner.org/optimize/以及其他链接https://stackoverflow.com/tags/x86/info

说真的,我只是没有看到任何合理的理由为什么你会认为编译器可能想要使用xchg,特别是考虑到调用约定不会在 RAX 中传递参数,因此您仍然需要 2 条指令。即使对于寄存器来说,xchg reg,reg在 Intel CPU 上是 3 uops,它们是无法从 mov-elimination 中受益的微代码 uops。 (一些 AMD CPU 有 2-uopxchg reg,reg. 为什么 XCHG reg, reg 在现代 Intel 架构上是 3 微操作指令?)


我还猜你正在查看 clang 输出;GCC 将避免部分注册恶作剧(如错误的依赖关系)通过使用movzx eax, byte ptr [rsi]即使返回值只是低字节,也会加载。零扩展加载比合并到 RAX 的旧值更便宜。所以这是另一个缺点xchg.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 clang 和 GCC 不使用 xchg 来实现 std::swap? 的相关文章

  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 汇编程序中的过程调用如何工作?

    我刚刚开始摆弄 ASM 我不确定我对过程调用的理解是否正确 假设代码中的某个时刻有一个过程调用 call dword ptr 123 该过程仅包含一个命令 ret ret 0004 该过程调用的效果是什么 返回值将存储在哪里 我在某处读到
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐