标签: compiler-optimization

如何在gcc中禁用编译器优化?

我正在努力学习汇编语言.我搜索并发现如何反汇编.c文件,但我认为它产生了一些优化版本的程序.有什么办法可以让我看到与我的C文件对应的确切汇编代码.

c gcc compiler-optimization compiler-options

69
推荐指数
5
解决办法
9万
查看次数

编译器优化会引入错误吗?

今天我和我的一个朋友进行了讨论,我们就"编译器优化"进行了几个小时的讨论.

我辩护说,有时,编译器优化可能会引入错误或至少是不良行为.

我的朋友完全不同意,他说"编译器是由聪明人构建并做聪明的东西",因此永远不会出错.

他根本没有说服我,但我不得不承认我缺乏现实生活中的例子来强化我的观点.

谁在这?如果是的话,您是否有任何现实生活中的例子,编译器优化会在生成的软件中产生错误?如果我错了,我应该停止编程并学习钓鱼吗?

compiler-construction optimization compiler-optimization

68
推荐指数
10
解决办法
2万
查看次数

为什么memcmp(a,b,4)有时只针对uint32比较进行优化?

鉴于此代码:

#include <string.h>

int equal4(const char* a, const char* b)
{
    return memcmp(a, b, 4) == 0;
}

int less4(const char* a, const char* b)
{
    return memcmp(a, b, 4) < 0;
}
Run Code Online (Sandbox Code Playgroud)

x86_64上的GCC 7引入了第一种情况的优化(Clang已经做了很长时间):

    mov     eax, DWORD PTR [rsi]
    cmp     DWORD PTR [rdi], eax
    sete    al
    movzx   eax, al
Run Code Online (Sandbox Code Playgroud)

但第二种情况仍然是memcmp():

    sub     rsp, 8
    mov     edx, 4
    call    memcmp
    add     rsp, 8
    shr     eax, 31
Run Code Online (Sandbox Code Playgroud)

是否可以对第二种情况应用类似的优化?什么是最好的装配,有没有明确的理由为什么它没有完成(由GCC或Clang)?

在Godbolt的Compiler Explorer上看到它:https://godbolt.org/g/jv8fcf

c gcc x86-64 clang compiler-optimization

68
推荐指数
3
解决办法
3930
查看次数

De Morgan的Law优化与重载运算符

每个程序员都应该知道:

德摩根1
德摩根2
(德摩根定律)

在某些情况下,为了优化程序,编译器可能会修改(!p && !q)(!(p || q)).

这两个表达式是等价的,并且评估第一个或第二个没有区别.
但是在C++中,可能会重载运算符,而重载的运算符可能并不总是尊重这个属性.因此,以这种方式转换代码实际上将修改代码.

如果编译器使用德摩根定律时!,||&&超载?

c++ operator-overloading compiler-optimization language-lawyer

67
推荐指数
4
解决办法
3654
查看次数

如何关闭gcc编译器优化以启用缓冲区溢出

我正在处理一个需要禁用编译器优化保护才能工作的作业问题.我在ubuntu linux上使用gcc 4.4.1,但无法弄清楚哪些是正确的.我意识到它依赖于架构 - 我的机器运行32位英特尔处理器.

谢谢.

c gcc buffer-overflow compiler-optimization

66
推荐指数
5
解决办法
9万
查看次数

为什么GCC不能优化"x &&(x&4242)"到"x&4242"中的逻辑按位AND对?

以下是我声称完成同样事情的两个功能:

bool fast(int x)
{
  return x & 4242;
}

bool slow(int x)
{
  return x && (x & 4242);
}
Run Code Online (Sandbox Code Playgroud)

从逻辑上讲,他们做同样的事情,只是为了100%肯定我写了一个测试,通过他们两个运行所有40亿个可能的输入,并且他们匹配.但汇编代码是一个不同的故事:

fast:
    andl    $4242, %edi
    setne   %al
    ret

slow:
    xorl    %eax, %eax
    testl   %edi, %edi
    je      .L3
    andl    $4242, %edi
    setne   %al
.L3:
    rep
    ret
Run Code Online (Sandbox Code Playgroud)

令我感到惊讶的是,GCC无法实现消除冗余测试的逻辑上的飞跃.我用-O2,-O3和-Os尝试了g ++ 4.4.3和4.7.2,所有这些都生成了相同的代码.该平台是Linux x86_64.

有人可以解释为什么GCC不够聪明,不能在两种情况下生成相同的代码吗?我还想知道其他编译器是否可以做得更好.

编辑以添加测试工具:

#include <cstdlib>
#include <vector>
using namespace std;

int main(int argc, char* argv[])
{
    // make vector filled with numbers starting from argv[1]
    int seed = atoi(argv[1]);
    vector<int> v(100000); …
Run Code Online (Sandbox Code Playgroud)

c++ optimization gcc compiler-optimization

66
推荐指数
6
解决办法
6652
查看次数

为什么std :: fill(0)比std :: fill(1)慢?

我在一个系统std::fill上观察到,与常量值或动态值相比,std::vector<int>设置常量值时,大型系统显着且持续地较慢:01

5.8 GiB/s vs 7.5 GiB/s

但是,对于较小的数据大小,结果是不同的,其中fill(0)更快:

不同数据大小的单线程性能

对于4个GiB数据大小的多个线程,fill(1)显示更高的斜率,但达到的峰值远低于fill(0)(51 GiB/s对90 GiB/s):

大数据大小的各种线程计数的性能

这提出了次要问题,为什么峰值带宽fill(1)要低得多.

测试系统是一个双插槽Intel Xeon CPU E5-2680 v3,设置为2.5 GHz(通道/sys/cpufreq),带有8x16 GiB DDR4-2133.我使用GCC 6.1.0(-O3)和英特尔编译器17.0.1(-fast)进行了测试,结果都相同.GOMP_CPU_AFFINITY=0,12,1,13,2,14,3,15,4,16,5,17,6,18,7,19,8,20,9,21,10,22,11,23被设定了.Strem/add/24个线程在系统上获得85 GiB/s.

我能够在不同的Haswell双插槽服务器系统上重现这种效果,但没有任何其他架构.例如在Sandy Bridge EP上,内存性能是相同的,而在缓存fill(0)中则要快得多.

这是重现的代码:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <omp.h>
#include <vector>

using value = int;
using vector = std::vector<value>;

constexpr size_t write_size = 8ll * 1024 * 1024 * 1024;
constexpr size_t …
Run Code Online (Sandbox Code Playgroud)

c++ performance x86 memset compiler-optimization

65
推荐指数
2
解决办法
2366
查看次数

为什么现代编译器不合并相邻的内存访问?

考虑以下代码:

bool AllZeroes(const char buf[4])
{
    return buf[0] == 0 &&
           buf[1] == 0 &&
           buf[2] == 0 &&
           buf[3] == 0;
}
Run Code Online (Sandbox Code Playgroud)

Clang 13 的输出组件-O3

AllZeroes(char const*):                        # @AllZeroes(char const*)
        cmp     byte ptr [rdi], 0
        je      .LBB0_2
        xor     eax, eax
        ret
.LBB0_2:
        cmp     byte ptr [rdi + 1], 0
        je      .LBB0_4
        xor     eax, eax
        ret
.LBB0_4:
        cmp     byte ptr [rdi + 2], 0
        je      .LBB0_6
        xor     eax, eax
        ret
.LBB0_6:
        cmp     byte ptr [rdi + 3], 0 …
Run Code Online (Sandbox Code Playgroud)

c++ optimization assembly compiler-optimization

65
推荐指数
3
解决办法
4215
查看次数

/ Ox和/ O2编译器选项有什么区别?

Microsoft的C++编译器(cl.exe包含在Visual Studio中)提供了几个优化开关.大多数它们之间的差异似乎是不言自明的,但我不清楚它之间的区别/O2(它优化代码以获得最大速度)和/Ox(选择"完全优化").

我试着阅读文档/Ox选项,它似乎证实,该交换机还支持优化的最高速度,而不是大小:

所述/Ox编译器选项产生在较小尺寸有利于代码的执行速度.

但特别是,"备注"部分下面的声明引起了我的注意:

通常,指定/O2(最大化速度)而不是/Ox.

所以我的问题是,为什么要一个普遍青睐/O2/Ox后一个选项是否允许已知的特定优化导致无法预料的错误或其他意外行为?是否只是获得的优化量不值得额外的编译时间?或者这只是一个完全没有意义的"推荐",因为它/O2是VS中的默认选项?

c++ compiler-optimization compiler-options visual-studio visual-c++

64
推荐指数
2
解决办法
2万
查看次数

GCC如何优化循环内增加的未使用变量?

我写了这个简单的C程序:

int main() {
    int i;
    int count = 0;
    for(i = 0; i < 2000000000; i++){
        count = count + 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想看看gcc编译器如何优化这个循环(显然添加1 2000000000次应该是"一次添加2000000000 ").所以:

GCC test.c的,然后timea.out给出了:

real 0m7.717s  
user 0m7.710s  
sys 0m0.000s  
Run Code Online (Sandbox Code Playgroud)

$ gcc -O2 test.c 然后time ona.out`给出:

real 0m0.003s  
user 0m0.000s  
sys 0m0.000s  
Run Code Online (Sandbox Code Playgroud)

然后我用两个人拆开了gcc -S.第一个似乎很清楚:

    .file "test.c"  
    .text  
.globl main
    .type   main, @function  
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, …
Run Code Online (Sandbox Code Playgroud)

c gcc disassembly compiler-optimization

64
推荐指数
1
解决办法
7410
查看次数