- 已关闭**。此问题需要details or clarity。当前不接受答案。
- 想要改进此问题?**添加详细信息并通过editing this post阐明问题。
2天前关闭。
Improve this question
enter image description hereCodeasm diff
我不是很明白这是什么优化,我只知道它真的很快,我已经尝试了手册中的许多命令都没有用。谁能详细解释一下这是什么优化,以及GCC中的哪个命令可以生成与ICC相同或更好的ASM?
2天前关闭。
Improve this question
enter image description hereCodeasm diff
我不是很明白这是什么优化,我只知道它真的很快,我已经尝试了手册中的许多命令都没有用。谁能详细解释一下这是什么优化,以及GCC中的哪个命令可以生成与ICC相同或更好的ASM?
2条答案
按热度按时间d7v8vwbk1#
我不确定是否有一个优化选项可以让GCC做这个优化。如果你不想让你的程序花时间做同样的事情,就不要写重复10万次的循环。
击败基准循环可以使编译器在基准测试中看起来很好,但是AFAIK在实际代码中通常没有用,因为在您想要优化的循环运行之间会发生其他事情。
ICC将您的基准重复循环转换为以下形式,从而击败了它
第一步是交换内部循环和外部循环,称为loop interchange。对数组进行一次遍历有利于缓存局部性,并支持进一步优化。
将
for() if()
转换为if() for(){} else for(){}
称为loop unswitching,在这种情况下,没有“其他”工作要做;循环中唯一的东西是if()sum+=...
,所以它变成仅仅是控制重复加法循环的if。ICC展开+矢量化
sum +=
,奇怪的是,它不只是用乘法来做,而是用100000
64位加法运算。ymm 0保存vpbroadcastq
中的_mm256_set1_epi64(data[c])
。此内部循环只有条件地运行;如果要保存这个循环的6250次迭代,就值得进行分支(只遍历数组一次,每个元素一次分支,而不是100 k)。
每次迭代执行16次加法,每条指令4次,按4展开到单独的累加器中,累加器减为1,然后在循环后进行h求和。展开允许Skylake和以后的版本在每个时钟周期运行3
vpaddq
。相比之下,GCC在数组上执行多次传递,在循环内向量化以无分支地执行8次比较:
这是在一个重复循环内部,该循环在数组上进行多次传递,并且可能在每个时钟周期1个shuffle微操作时出现瓶颈,就像Skylake上每3个时钟周期8个元素一样。
所以它只是像你所期望的那样向量化了内部的
if() sum+=data[c]
,根本没有破坏repeat循环。ippsafx72#
编译器生成功能上等同的代码,没有理由假设从一个输入到目标有一个完美的输出。如果两个编译器为相对合适大小的函数/项目生成相同的输出,那么一个编译器是从另一个编译器派生的,合法与否。
一般来说,没有理由假设任何两个编译器生成相同的输出,或者同一个编译器的任何两个版本生成相同的输出。通过命令行选项来放大这一点,这些选项将改变编译器的输出。
一般来说,人们期望一个编译器能为你的代码生成“更好”的代码,这取决于“更好”、“更小”或“在一台特定的计算机、操作系统等上运行得更快”的定义。
gcc是一种通用计算机,它对每个目标都“不错”,但对任何目标都不是很好。一些从头开始设计的针对一个目标/系统的工具可以(但不一定)做得更好。然后可能会有一些欺骗。以一些代码为例,比如可能是故意写得很糟糕的Drystone和Whetstone,那么当X编译器,也许你已经付出(五位数)为或正在评估支付,不产生代码的dhrystone是一样快的免费工具。哦,当然,尝试这个命令行选项为dhrystone.嗯好的,这样做更好(到过那里,gcc自从3.x.x/4.x.x.版本以来一直在变差。我认为原因是多方面的。我认为,部分原因是真正在这一级别工作的人正在死亡,并被没有低水平经验和技能的人所取代。处理器变得越来越复杂,gcc和其他公司有了更多的目标,但是老版本提供的优化失败的数量在增加,同样的源代码和设置的二进制文件的大小也在增加,增加的幅度很大,对于一个规模合适的项目来说,不仅仅是一点点。
这不是一个情况下,我需要得到车轮上的汽车,我有一个工具的选择,我可以用来拧紧螺母,这是相同的结果独立于工具。
没有理由期望任何两个编译器可以生成相同的输出,即使这两个工具都生成汇编语言,并且生成相同的指令和数据序列,也没有理由假设汇编语言本身来自用于该目标的不同汇编语言,不同的标签名称和间距、函数排序以及其他会使diff难以处理的语法。