为什么 gcc 12.2 不优化从 main() 调用的 constexpr 函数中的除法到移位

2023-12-06

我一直在使用 Godbolt 编译器并输入以下代码:

constexpr int func(int x)
{
    return x > 3 ? x * 2 : (x < -4 ? x - 4 : x / 2);
}

int main(int argc)
{
    return func(argc);
}

代码有点简单。这里重要的部分是最后除以2func(int x)。由于 x 是一个整数,基本上任何编译器都会将其简化为移位以避免除法指令。

x86-64 gcc 12.2 的汇编-O3(对于 Linux,因此 System V ABI)如下所示:

main:
        cmp     edi, 3
        jle     .L2
        lea     eax, [rdi+rdi]
        ret
.L2:
        cmp     edi, -4
        jge     .L4
        lea     eax, [rdi-4]
        ret
.L4:
        mov     eax, edi
        mov     ecx, 2
        cdq
        idiv    ecx
        ret

你可以看到决赛idiv ecx命令不是移位,而是实际除以 2。我还测试了 clang,clang 实际上将其减少为移位。

main:                                   # @main
        mov     eax, edi
        cmp     edi, 4
        jl      .LBB0_2
        add     eax, eax
        ret
.LBB0_2:
        cmp     eax, -5
        jg      .LBB0_4
        add     eax, -4
        ret
.LBB0_4:
        mov     ecx, eax
        shr     cl, 7
        add     cl, al
        sar     cl
        movsx   eax, cl
        ret

这可能是由于内联吗?我很好奇这里发生了什么。


海湾合作委员会对待main特别是:隐式__attribute__((cold))

So main得到的优化较少(或者更注重大小而不是速度),因为它在大多数程序中通常只调用一次。__attribute__((cold))不太一样-Os(优化大小),但这是朝这个方向迈出的一步,有时会得到成本启发来选择一个简单的除法指令。

As GCC 开发者 Marc Glisse 评论, 不要将代码放入名为的函数中main如果您正在对其进行基准测试或查看它如何优化。(除此之外还可以有其他特殊的东西cold,例如MinGW GCC 额外添加了call到 init 函数,以及gcc -m32添加代码以按 16 对齐堆栈。对于您正在查看的代码来说,所有这些都是您不希望看到的噪音。也可以看看如何从 GCC/clang 汇编输出中消除“噪音”?)

另一个问答显示 GCC 推杆main in the .text.startup部分,以及其他假定的“冷”功能。 (这对于 TLB 和分页局部性有好处;希望整个 init 函数页面可以在进程启动后被逐出。这个想法是代码在main可能只运行一次,真正的工作发生在它调用的某个函数内。如果实际工作内联到 main 中,或者对于简单的程序,情况可能并非如此。)

对于所有代码都在其中的玩具程序来说,这是一个糟糕的启发式方法main,但这就是 GCC 所做的。人们经常运行的大多数真实程序aren't玩具,并且在其他一些函数中有足够的代码,但它没有内联到其中main。尽管如果启发式方法能更聪明一点并删除cold如果事实证明整个程序或循环中的所有函数确实优化为main,因为一些实际的程序非常简单。

您可以使用以下方法覆盖启发式GNU C 函数属性.

  • __attribute__((hot)) int main(){ ...以您期望的方式优化
    (Godbolt from 索佩尔的评论,添加了属性)。
  • __attribute__((cold))在未调用的函数上main产生idiv.
  • __attribute__((optimize("O3")))没有帮助。

int main(int x, char **y){ return x/2; } does仍然使用轮班gcc -O2,所以主要是cold并不总是有这种效果(不像-Os).

但也许你的除法已经是有条件的,GCC 猜测基本块甚至不会每次都运行,所以更有理由让它小而不是快。


疯狂的是,海湾合作委员会-Os对于 x86-64(神箭)确实使用idiv对于有符号除法,常数 2,而不仅仅是任意常数(其中 GCC 通常使用乘法逆元即使在-O0)。如果任何代码大小与带有修正舍入到零(而不是 -inf)的算术右移相比,它不会节省太多,并且可以是much速度较慢,特别是对于 Ice Lake 之前的 Intel 上的 64 位整数。与 AArch64 相同,无论哪种方式都是 2 个固定大小的指令,其中sdiv几乎肯定会慢得多。

sdiv确实在 AArch64 上节省了一些代码大小,以获得更高的 2 次幂(Godbolt),但仍然慢得多,这可能不是一个好的权衡-Os. idiv不保存 x86-64 上的指令(如cdq or cqo需要转换为 RDX),尽管代码大小可能只有几个字节。所以可能只适合-Oz它也会使用的地方push 2 / pop rcx将一个小常量放入寄存器中3 个字节的 x86-64 机器代码而不是 5 个.

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

为什么 gcc 12.2 不优化从 main() 调用的 constexpr 函数中的除法到移位 的相关文章

  • 无法在 QGLWidget 中设置所需的 OpenGL 版本

    我正在尝试在 Qt 4 8 2 中使用 QGLWidget 我注意到 QGLWidget 创建的默认上下文不显示 OpenGL 3 1 以上的任何输出 Qt wiki 有一个教程 http qt project org wiki How t
  • 并行运行多个任务

    我有一个代理列表 每个代理都会访问不同的站点并从站点中提取所需的数据 目前它一次只做一个 但我希望同时运行 10 20 个任务 这样它就可以一次性从 20 个站点下载 而不是只下载一个 这是我目前正在做的事情 private async T
  • 如何在 C++ 中为指针“this”赋值

    在函数中 如何分配this一个新的价值 您可以分配对象this点于 this XY 但你不能分配直接值this this XY Error Expression is not assignable
  • 每个元素的 asp.net Web 表单自定义错误消息

    我创建了一个 Web 应用程序 表单 以及后端 SQL 插入和查询 目前我正在显示所有用户错误消息 div style padding 1em div
  • 如何在 C# 中以编程方式将行添加到 DataGrid?

    正如标题所述 我正在尝试使用 C 以编程方式将行添加到 DataGrid 但我似乎无法使其工作 这是我到目前为止所拥有的 I have a DataGrid declared as dg in the XAML foreach string
  • 维护 VS Test Project 中单元测试方法之间的上下文

    我想按顺序运行以下单元测试 使用随机数字的名称 密码等创建新客户 检索刚刚创建的客户并断言其属性包含相同的随机数 对同一用户调用 ForgotPassword 函数 并使用相同的随机数作为用户名 清楚地看到 我需要生成一次随机数 并在 3
  • 加载 QPixmap 数据的更好方法

    更好的方法来做到这一点 没有QImage QImage image width height QImage Format RGB888 memcpy image bits m frameRGB gt data 0 height width
  • 从图像创建半透明光标

    是否可以从图像创建光标并使其半透明 我目前正在拍摄自定义图像并覆盖鼠标光标图像 如果我可以将其设为半透明 那就太好了 但不是必需的 销售人员喜欢闪亮的 目前正在做这样的事情 Image cursorImage customImage Get
  • 注入包含接口的所有已注册实现的 Enumerable

    给出以下接口 public interface IMyProcessor void Process 我希望能够注册多个实现 并让我的 DI 容器将它们的可枚举注入到这样的类中 public class MyProcessorLibrary
  • 如何在 C 中链接目标文件?失败并显示“架构 x86_64 的未定义符号”

    因此 我尝试在我的文件 file2 c 中使用另一个 C file1 c 文件中定义的函数 为了做到这一点 我包含了 file1 file1 h 的标头 但是 每当我尝试使用 gcc 编译文件时 我都会收到以下错误 Undefined sy
  • 使用 STL 流时如何格式化我自己的对象?

    我想将我自己的对象输出到 STL 流 但具有自定义格式 我想出了这样的东西 但由于我之前从未使用过 locale 和 imbue 所以我不知道这是否有意义以及如何实现 MyFacet 和operator 所以我的问题是 这是否有意义以及如何
  • 如何在 C++ 中正确使用 cin.fail()

    我正在编写一个程序 从用户那里获取整数输入cin gt gt iUserSel 如果用户输入一个字母 程序就会进入无限循环 我试图用下面的代码来阻止这种情况 但程序进入无限循环并打印出 错误 输入 我该如何修复我的程序 cin gt gt
  • 当我尝试传递临时地址作为参数时,它是一个 UB 吗?

    对于以下 C 代码 include
  • 从单应性估计 R/T

    我一直在尝试计算 2 个图像中的特征 然后将这些特征传递回CameraParams R没有运气 特征已成功计算并匹配 但是问题是将它们传递回R t 我明白你必须分解Homography为了使这一点成为可能 我已经使用如下方法完成了 http
  • 具有多个父项的 Qt 树模型

    我想构建一棵树 其中一个元素可以引用另一个元素 我想要构建的树是 像这样的东西 A B C D E F P this is a pointer to C D first child of C E second child of C I fo
  • 在 Visual Studio 2012 Express 中设置 C++ 调试环境

    我需要调试的应用程序需要设置环境变量 这在 Visual Studio 2012 中似乎非常复杂 我想做类似的事情 set path c foo c bar c windows c program files application set
  • 使用未命名命名空间而不是静态命名空间

    我可以假设在未命名命名空间中声明的对象相当于static namespace int x 1 static int x 2 FWIK 在这两种情况下 x将具有静态存储期限和内部链接 声明为的对象的所有规则也是如此static适用于未命名名称
  • c++ - <未解析的重载函数类型>

    在我的班级里叫Mat 我想要一个将另一个函数作为参数的函数 现在我有下面 4 个函数 但是在调用 print 时出现错误 第二行给了我一个错误 但我不明白为什么 因为第一行有效 唯一的区别是功能f不是班级成员Mat but f2是 失败的是
  • 跟踪白色背景中的白球(Python/OpenCV)

    我在 Python 3 中使用 OpenCV 来检测白场上的白 黑球 并给出它的精确 x y 半径 和颜色 我使用函数 cv2 Canny 和 cv2 findContours 来找到它 但问题是 cv2 Canny 并不总是检测到圆的完整
  • 使用空的weak_ptr作为参数调用map::count安全吗?

    打电话安全吗map count http www cplusplus com reference map map count on an 未初始化因此为空weak ptr http en cppreference com w cpp mem

随机推荐

  • 使用 Elmah 记录 WCF Web 服务的用户名

    我们正在使用描述的方法here使用 Elmah 记录我们的 Web 服务错误 这确实有效 但遗憾的是记录的用户名是空的 我们做了一些调试 发现在 ErrorHandler 中记录错误时HttpContext Current User具有正确
  • Windows Phone ApplicationBar BackgroundColor 属性样式 XamlParseException

    我的应用程序中有很多页面 我决定在 App Resources 中创建一个全局 ApplicationBar 样式 然而 当我尝试启动应用程序时 VS 给了我一个错误 The property BackgroundColor was not
  • 在 PHP 安装上启用 Mcrypt

    我使用 Apache 2 2 16 在 Windows 机器上安装了 PHP 5 2 14 通过 msi 安装 安装附带了 ext php mcrypt dll 和 libmcrypt dll 但当我取消注释时扩展名 php mcrypt
  • Sql PIVOT 和字符串连接聚合

    我想使用数据透视 SQL 查询来构造一个结果表 其中连接文本作为数据透视表的数据部分中的结果 即我使用简单的选择得到以下结果 Event Name Resource Type Resource Name Event 1 Resource T
  • web.xml 中使用 CharacterEncodingFilter 进行 Spring 编码

    stackoverflow com 上的编码 我的网站上的编码
  • 将 JXTable 与 RXTable 组合

    Problem 我想要的能力JXTable与 编辑时全选 行为RXTable 进行简单的覆盖就可以了 但是 RXTable 的双击功能不适用于 JXTable 当使用 按钮操作 模式时 这很好 但是当使用 F2 或双击 JXTable 中的
  • 为什么函数的地址会随着每次运行而改变?

    我正在努力将地址映射到其符号以进行调试 获取调用堆栈 MS dbghelp dll 可以从地址中识别符号 请参阅SymFromAddr MSDN 然而 它不起作用 我想知道这是如何工作的 因为地址似乎随着程序的每次运行而改变 include
  • 如何解释 CPU 窗口反汇编窗格中的列?

    There is a tool called the CPU window which I get pressing Ctrl Alt C that shows the disassembly of my code 内存地址左边的绿色箭头表
  • 突出显示和过滤 (gcc) 编译器消息

    我目前正在重构一个 C 项目 向我抛出大约 1000 个警告 有没有办法突出显示和过滤这些警告 例如 将所有索引警告设置为红色 未使用的警告设置为蓝色 以及其他一些警告 很可能有些IDE可以做到这一点 但这对我来说不是解决方案 This i
  • 找不到模块“minizlib”

    我对 React Native 还很陌生 我使用下面的代码在我的 Mac 上安装 React Native npm install react native g react native cli 我收到错误 npm ERR code MOD
  • 现代 Android 中的非合作 Thread.stop() 替代方案

    Thread stop 现已从现代 Android API 中删除 从https developer android com reference java lang Thread stop 用途广泛 of stop应替换为仅修改某些变量以指
  • 为什么 `i = ++i + 1` 是未指定的行为?

    请考虑以下 C 标准 ISO IEC 14882 2003 E 引文 第 5 节第 4 段 除非另有说明 顺序 个别操作数的评估 个体的运算符和子表达式 表达式和顺序 发生哪些副作用 是 未指定 53 之前之间 下一个序列指向标量 对象应有
  • Android 有没有好的图表库?

    我需要在我正在开发的 Android 应用程序中渲染和显示图表 目前是条形图 但以后可能需要更多类型 我环顾四周 似乎还没有任何真正优秀 成熟的 Android 图表库 你知道任何 编辑以添加一些要求的详细信息 条形图 水平条形图 双堆叠条
  • 在外部定义的函数上使用 lapply

    这个问题与R 将固定列传递给 data table 中的 lapply 函数 and 按组和列的加权平均值 但又有些不同 我希望有一个固定列与同一列中的所有其他列进行交互data table 一个简单的例子来说明 DT lt data ta
  • 无法登录 Docker 帐户

    OS Ubuntu 18 04 Server Docker 18 3 CE 我使用 PuTTY SSH 会话从 Windows 10 笔记本电脑登录到服务器 我的本地 Windows 笔记本电脑上没有 Docker 因此所有工作都在远程服务
  • iPhone 摇动事件无法正常工作

    我的 viewController 中有这个 void motionEnded UIEventSubtype motion withEvent UIEvent event if event type UIEventSubtypeMotion
  • 未知错误:调用函数结果缺少“值”Appium 混合应用程序

    我在将密钥发送到某些字段时遇到问题 driver findElement By xpath id login main a click Thread sleep 1000 driver findElement By xpath html b
  • 同时为多个社交网络启用OAuth2Sso

    我正在实现一个 Spring Boot 应用程序 需要提供 OAuth2 令牌授权并支持多种社交服务 google facebook 等 用户应该能够选择他喜欢的社交网络并使用 OAuth2 授权框架登录 我正在使用此处描述的方法来实现上述
  • 使用可选标签反序列化 XML

    我有一个带有可选标签的 XML 如下所示
  • 为什么 gcc 12.2 不优化从 main() 调用的 constexpr 函数中的除法到移位

    我一直在使用 Godbolt 编译器并输入以下代码 constexpr int func int x return x gt 3 x 2 x lt 4 x 4 x 2 int main int argc return func argc 代