我有一组 POD 结构,并试图对一个字段求和。这是一个最小的例子:
struct Item
{
int x = 0;
int y = 0;
};
typedef Item Items[2];
struct ItemArray
{
Items items;
int sum_x1() const;
int sum_x2() const;
};
int ItemArray::sum_x1() const
{
int total = 0;
for (unsigned ii = 0; ii < 2; ++ii)
{
total += items[ii].x;
}
return total;
}
int ItemArray::sum_x2() const
{
int total = 0;
for (const Item& item : items)
{
total += item.x;
}
return total;
}
这两个 sum 函数做同样的事情。 Clang 以相同的方式编译它们。但是 x86_64 上带有 -O3 的 GCC 6 没有。这是 sum_x1(),看起来不错:
mov eax, DWORD PTR [rdi+8]
add eax, DWORD PTR [rdi]
ret
现在看sum_x2():
lea rdx, [rdi+16]
lea rcx, [rdi+8]
xor eax, eax
add eax, DWORD PTR [rdi]
cmp rdx, rcx
je .L12
lea rcx, [rdi+16]
add eax, DWORD PTR [rdi+8]
cmp rdx, rcx
je .L2
lea rcx, [rdi+24]
add eax, DWORD PTR [rdi+16]
cmp rdx, rcx
je .L2
lea rcx, [rdi+32]
add eax, DWORD PTR [rdi+24]
cmp rdx, rcx
je .L2
lea rcx, [rdi+40]
add eax, DWORD PTR [rdi+32]
cmp rdx, rcx
je .L2
lea rcx, [rdi+48]
add eax, DWORD PTR [rdi+40]
cmp rdx, rcx
je .L2
lea rcx, [rdi+56]
add eax, DWORD PTR [rdi+48]
cmp rdx, rcx
je .L2
lea rcx, [rdi+64]
add eax, DWORD PTR [rdi+56]
cmp rdx, rcx
je .L2
lea rcx, [rdi+72]
add eax, DWORD PTR [rdi+64]
cmp rdx, rcx
je .L2
add eax, DWORD PTR [rdi+72]
ret
.L2:
rep ret
.L12:
rep ret
当循环长度固定为 2 时,为什么 GCC 会发出一个长度不超过 10 的展开循环?它只在成员函数中执行此操作——使 sum_x2 成为一个免费函数来修复它。
ICC 还非常奇怪地优化了 sum_x2(),尽管生成的代码完全不同。与 GCC 不同,sum_x2() 是成员函数还是自由函数并不重要——两者都是错误的。
我使用的是 GCC 6,但所有版本的 GCC 似乎都存在此代码的问题。添加 -march=haswell 会使情况变得更糟,在大小为 2 的数组中添加最多 15 个元素的迭代。GCC 5 和 7 会生成更复杂的代码,添加 SIMD 指令。
我想确定这个问题的确切原因,以便我可以在我的代码中找到并修复类似的情况。了解在 GCC 6 中触发此行为的原因将非常有帮助。我的代码中有很多基于范围的 for 循环,对于删除它们的前景我并不太兴奋,但如果 GCC 不能生成合理的代码,我将别无选择。
试试看:https://godbolt.org/g/9GK4jy
更多相关的精神错乱:https://godbolt.org/g/BGYggD (最佳代码是 3 条指令;GCC 6 产生 8 条指令;GCC 7 产生 130 条指令)
最佳答案
正如 Richard Biener 在我的 bug report 中所描述的那样,问题似乎是版本 8 之前的 GCC 无法理解类或结构的字段与常规变量一样受到相同的优化(例如常量循环计数)。所以它会发出各种花哨的代码来优化循环未知次数,即使它在编译时已知,在容器是成员变量的情况下。
按照我的理解,这个错误可能会影响相当多的代码——例如在任何地方,成员小数组都是 C++11 基于范围的 for 循环的主题。
感谢 Richard Biener 的及时解决(针对 GCC 8)。
关于c++ - GCC 优化基于固定范围的 for 循环,就好像它有更长的可变长度一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45496987/
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai
我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种
当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?
在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"
目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi