循环展开优化,它是如何工作的

2024-03-31

考虑这个 C 代码:

int sum=0;
for(int i=0;i<5;i++)
    sum+=i;

这可以用(伪)汇编方式翻译(无需循环展开):

% pseudo-code assembly
ADDI $R10, #0   % sum
ADDI $R11, #0   % i
LOOP:
ADD $R10, $R11
ADDI $R11, #1
BNE $R11, #5 LOOP

所以我的第一个问题是如何使用循环展开来翻译这段代码,在这两种方式之间:

1)

ADDI $R10, #0
ADDI $R10, #0
ADDI $R10, #1
ADDI $R10, #2
ADDI $R10, #3
ADDI $R10, #4

2)

   ADD $R10, #10

编译器是否能够优化代码并直接知道它必须加 10 而无需执行所有求和?

另外,是否有可能用分支指令阻塞管道?我必须这样写吗:

% pseudo-code assembly
ADDI $R10, #0   % sum
ADDI $R11, #0   % i
LOOP:
ADD $R10, $R11
ADDI $R11, #1
NOP   % is this necessary to avoid the pipeline blocking?
NOP
NOP
NOP
BNE $R11, #5 LOOP

为了避免 fetch-decode-exe-mem-write back 周期被分支中断?


这更多的是为了演示编译器是什么有能力,而不是每个编译器都会做的事情。来源:

#include <stdio.h>

int main(void)
{
    int i, sum = 0;

    for(i=0; i<5; i++) {
        sum+=i;
    }

    printf("%d\n", sum);
    return 0;
}

请注意printf我已经添加了。如果不使用该变量,编译器将优化整个循环。

使用 -O0 编译(无优化)

gcc -Wall -O0 -S -c lala.c:

.L3:
    movl    -8(%rbp), %eax
    addl    %eax, -4(%rbp)
    addl    $1, -8(%rbp)
.L2:
    cmpl    $4, -8(%rbp)
    jle .L3

循环以“愚蠢”的方式发生,-8(%rbp)是变量i.

使用 -O1 编译(优化级别 1)

gcc -Wall -O1 -S -c lala.c:

movl    $10, %edx

循环已被完全删除并替换为等效值。


在展开过程中,编译器会查看会发生多少次迭代,并尝试通过执行更少的迭代来展开。例如,循环体可能会重复两次,这将导致分支数量减半。 C 中存在这样的情况:

int i = 0, sum = 0;

sum += i;
i++;

for(; i<5;i++) {
    sum+=i;
    i++;
    sum+=i;
}

请注意,必须从循环中提取一次迭代。因为5是奇数,所以不能简单地通过复制内容来减半工作量。在这种情况下,循环只会进入两次。产生的汇编代码-O0:

    movl    -8(%rbp), %eax
    addl    %eax, -4(%rbp)
    addl    $1, -8(%rbp)
    jmp .L2
.L3:
    movl    -8(%rbp), %eax
    addl    %eax, -4(%rbp)
    addl    $1, -8(%rbp)
    movl    -8(%rbp), %eax
    addl    %eax, -4(%rbp)
    addl    $1, -8(%rbp)
.L2:
    cmpl    $4, -8(%rbp)

在 C 中完全展开:

for(i=0; i<5;i++) {
    sum+=i;
    i++;
    sum+=i;
    i++;
    sum+=i;
    i++;
    sum+=i;
    i++;
    sum+=i;
}

这次实际上只进入了一次循环。生产的组件-O0:

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

循环展开优化,它是如何工作的 的相关文章

  • 如何知道并加载特定文件夹中的所有图像?

    我有一个应用程序 C Builder 6 0 需要知道特定文件夹中的图像总数 然后我必须加载它们 在 ImageList 或 ComboBoxEx 中 或任何其他控件中 我怎样才能做到这一点 我知道如何在控件中加载图像 或保存在 TList
  • boost线程在中断时不打印退出消息

    我有这段代码用于执行三个线程 其中第二个线程应在按 Enter 时中断并打印退出消息 void input val DO STUFF return void process val DO STUFF try cout lt lt waiti
  • .NET 可移植类库中的 .ToShortDateString 发生了什么

    我想知道为什么没有 ToShortDateString在 NET 可移植类库中 我有 2 个项目 Silverlight 和常规 NET 类库 使用相同的代码 并且代码涉及调用 ToShortDateString on a DateTime
  • 字节到二进制字符串 C# - 显示所有 8 位数字

    我想在文本框中显示一个字节 现在我正在使用 Convert ToString MyVeryOwnByte 2 但是 当字节开头有 0 时 这些 0 就会被删除 例子 MyVeryOwnByte 00001110 Texbox shows g
  • 对数字进行向上和向下舍入 C++

    我试图让我的程序分别向上和向下舍入数字 例如 如果数字是3 6 我的程序应该四舍五入最接近的数字 4 如果该数字是3 4 它将向下舍入为 3 我尝试使用ceil库获取 3 个项目的平均值 results ceil marks1 marks2
  • 控制台应用程序 .net Core 2.0 的配置

    在 net Core 1 中我们可以这样做 IConfiguration config new ConfigurationBuilder AddJsonFile appsettings json true true Build 这样就可以使
  • 推送 Lua 表

    我已经创建了一个Lua表C 但我不知道如何将该表推入堆栈顶部 以便我可以将其传递给 Lua 函数 有谁知道如何做到这一点 这是我当前的代码 lua createtable state libraries size 0 int table i
  • 如何在不使用reinterpret_cast的情况下使用dlsym()加载函数?

    我正在尝试使用 clang tidy 来强制执行 C 核心指南 虽然它确实有很多有效点 但有一件事我无法真正解决 dlsym 返回一个void 我需要以某种方式将其转换为正确的函数指针 为此 我使用reinterpret cast 由于指南
  • _mm_max_ss 在 clang 和 gcc 之间有不同的行为

    我正在尝试使用 clang 和 gcc 交叉编译一个项目 但在使用时发现一些奇怪的差异 mm max ss e g m128 a mm set ss std numeric limits
  • 当格式字符串包含“{”时,String.Format 异常

    我正在使用 VSTS 2008 C Net 2 0 执行以下语句时 String Format 语句抛出 FormatException 有什么想法是错误的吗 这是获取我正在使用的 template html 的位置 我想在 templat
  • 用 C# 编写的带有点击移动的 WPF 游戏

    我试图将标签网格移动到鼠标的位置 就像冒险游戏中的移动一样 理想情况下 我会在途中删除并重新绘制它们 但是 现在我只想弄清楚如何将 int 转换为厚度或 pointtoscreen 到目前为止我有 player XMove int Mous
  • C# ToString("MM/dd/yy") 删除前导 0 [重复]

    这个问题在这里已经有答案了 可能的重复 格式化 NET DateTime Day 不带前导零 https stackoverflow com questions 988353 format net datetime day with no
  • 为什么我不能在扩展 List 的类中调用 OrderBy?

    我有一堂课 Deck 其中包含一个名为的方法Shuffle 我正在致力于重构Deck延长List
  • 改进C++逐行读取文件的能力?

    我正在解析大约 500GB 的日志文件 我的 C 版本需要 3 5 分钟 我的 Go 版本需要 1 2 分钟 我正在使用 C 的流来流式传输文件的每一行以进行解析 include
  • 多个同名内存数据库

    关系到这个答案 https stackoverflow com a 48446491 596758 我试图通过设置让多个上下文工作UseInMemoryDatabase以同名 下面的测试失败 第二个上下文为空 我还需要做什么才能在内存数据库
  • 从 C# 中的 .NET SecureString 读取单个字符?

    WPF 的PasswordBox 返回一个SecureString 它对窥探者隐藏密码 问题是你最终必须获得密码的值 而我在网上找到的建议都涉及将值复制到字符串中 这会让你回到窥探者的问题 IntPtr bstr Marshal Secur
  • 如何使复选框不可选择?

    我想知道你是怎么做的CheckBox在c 中无法选择 我认为这会是类似 SetSelectable false 之类的东西 但我似乎看不到该方法 I found CanSelect但这似乎是只读属性 您可以设置自动检查 http msdn
  • 如何仅更改 DateTime 的日期部分,同时保留时间部分?

    我在代码中使用了很多 DateTime 我想将这些日期时间更改为我的特定日期并保留 时间 1 2012 02 02 06 00 00 gt 2015 12 12 06 00 00 2 2013 02 02 12 00 00 gt 2015
  • C++0x 中的新 unicode 字符

    我正在构建一个 API 它允许我获取各种编码的字符串 包括 utf8 utf16 utf32 和 wchar t 根据操作系统 可能是 utf32 或 utf16 新的 C 标准引入了新类型char16 t and char32 t没有这么
  • 最后从同一类中的其他构造函数调用构造函数

    我在这里读到可以调用另一个构造函数从同一类中的另一个构造函数调用构造函数 https stackoverflow com questions 829870 calling constructor from other constructor

随机推荐

  • 响应式设计,网站在手机上不滚动

    我正在设计一个响应式网站 它在桌面上运行良好 但当我在手机中测试时 我无法滚动页面 所以我只能看到适合设备高度的内容 注意 我什至包含了元名称 viewport 内容 宽度 设备宽度 initial scale 1 0 请帮我 你问这个问题
  • 使用 Keras 循环神经网络进行预测 - 准确度始终为 1.0

    TLDR 如何使用 Keras RNN 预测序列中的下一个值 我有一个连续值列表 我想将它们输入 RNNpredict序列中的下一个值 0 43589744 0 44230769 0 49358974 0 71153846 0 708333
  • PHP 脚本到 Traceroute?

    我有一个在 GoDaddy 共享 Linux 服务器上运行 PHP 的网站 我需要确定用户是否连接到公司 VPN 如果我简单地执行 SERVER REMOTE ADDR 它会给我客户端的 IP 地址 但是 如果我可以使用 Tracert 进
  • 无法使用 R 的 leaflet 包循环生成多个地图

    这是新来的 对 R 来说也相对较新 所以请原谅 apriori 并让我知道我在这篇文章中做错了什么 以避免将来烦扰其他人 我正在尝试创建传单地图序列 1971 年 9 月至 1972 年 4 月 最后 我想将它们压缩成闪亮的 并让用户播放
  • chrome.storage.local.set 使用变量键名

    在 Google Chrome 扩展中 我想使用chrome storage local http code google com chrome extensions storage html property local 与 localS
  • Xcode 7.2.1 的问题

    刚刚安装新版本的Xcode 7 2 1 他花了比预期更长的时间 但是当它完成并运行时 xcode 继续使用版本 7 1 1 我以为重启Mac就可以解决这个问题 但是没有 知道可以花什么吗 或者碰巧我已经完成了 EDITED 我的MAC版本
  • 如何修复从底部切掉的字体?

    我在应用程序中有自定义字体 我正在使用它Text如下 struct CustomButton View var label String var action gt Void init label String action escapin
  • Windows Phone Soap/添加 Web 参考问题

    我有一个 SOAP 由 Java 提供支持 服务 我正在尝试连接到 WP7 使用Add gt Service Reference生成代理客户端 但不幸的是 删除了 WP7 和 完整 NET 4 上方法的所有参数 使用 slsvcutil e
  • 原始计算器 - 动态方法

    我在获得以下问题的正确解决方案时遇到一些困难 你的目标是一个正整数n 找到最少的数量 从数字 1 开始获取数字 n 所需的操作 更具体地说 我在下面的评论中有测试用例 Failed case 3 16 Wrong answer got 15
  • 如何连接故事板中的原型单元?

    我在故事板中创建了一个表格视图 以及一个自定义原型单元 我已经在情节提要中设置了单元格标识符 并尝试将其出队并得到 无法使具有标识符 TTEntry 的单元出列 必须为标识符注册笔尖或类 或者连接故事板中的原型单元 我在情节提要 Table
  • 使用 python pty 伪终端进程发送命令并退出

    使用 python pty 模块 我想使用 stdin 函数 如 pty 模块想要的那样 向终端模拟器发送一些命令 然后强制退出 我想到了类似的事情 import pty cmnds exit n ls al n Command to se
  • Sun 的 bug 数据库中的 Java 版本名称

    In https bugs java com bugdatabase view bug bug id 6525150 https bugs java com bugdatabase view bug bug id 6525150它说 发布修
  • 如何在java中实现高效的超时

    有n执行某些操作的对象 执行操作后 时间戳将会更新 现在我想实现一个超时线程 它验证时间戳是否早于 60 秒 我的第一个解决方案是使用一个线程 while loop sleep 来做到这一点 该线程保存一个包含所有对象 包括最后一个时间戳
  • 使用 Visual Studio 创建大小为 100 字节的 C 程序

    我想编写一个 C 应用程序 该程序在构建时将创建一个大小为 100 字节或更小的可执行文件 即使我创建一个简单的 C 程序 其中只有一个空的main 我的输出文件在 Visual Studio 2015 上变成 11KB 有没有办法告诉 V
  • 在目录和子目录中搜索文件中的模式

    在Linux中 我想搜索给定目录及其子文件夹 文件以查找某些包含和排除模式 find apps exec grep performance v warn dev null 这与搜索所经过的大量行相呼应 我不想这样 我想找到包含性能但不包含警
  • 为什么这个 Jinja nl2br 过滤器会转义
    而不是

    我正在尝试实施this http flask pocoo org snippets 28 Jinja nl2br筛选 它工作正常 除了 br 是不是广告被转义了 这对我来说很奇怪 因为 p 没有被转义并且它们都在同一个字符串中 我正在使用烧
  • 可以将 std::numeric_limits 专门用于用户定义的类似数字的类吗?

    的文档std numeric limits
  • PHP 忽略 php.ini 中的curl.cainfo 设置(显然)

    我正在尝试修复 Windows 服务器 运行 IIS 上的 php curl 调用 该调用返回熟悉的错误 SSL 证书问题 请验证 CA 证书是否正常 详细信息 错误 14090086 SSL 例程 SSL3 GET SERVER CERT
  • 如何在 Apps 脚本中设置表格的水平对齐方式

    我无法找到使用 Google Apps 脚本水平对齐 Google 文档中表格的方法 我彻底检查了所有文档 也盲目地尝试了几种方法 尝试一 var cells Company rowData 3 Title rowData 4 var ta
  • 循环展开优化,它是如何工作的

    考虑这个 C 代码 int sum 0 for int i 0 i lt 5 i sum i 这可以用 伪 汇编方式翻译 无需循环展开 pseudo code assembly ADDI R10 0 sum ADDI R11 0 i LOO