c - 如果有的话,编译器什么时候会在指针取消引用优化方面保持保守?

标签 c pointers gcc optimization dereference

因此,我最近对编译器(gcc (GCC) 4.8.3 是有问题的编译器)在优化指针和指针方面的表现产生了兴趣。

最初我创建了一个简单的整数和一个整数指针并实现了 对其进行操作,以便我可以将其打印出来。正如预期的那样,所有操作 无论是否通过解除引用的指针,硬编码的内容都得到了优化。

call    __main
leaq    .LC0(%rip), %rcx
movl    $1, %edx
call    printf

甚至在创建了一个接受 int 指针的函数之后, 取消引用并更改它仍然是完美优化的。

call    __main
leaq    .LC0(%rip), %rcx
movl    $-1, %edx
call    printf

现在,当我将指针视为空指针并进行更改时 通过将它转换为 char 并取消引用它,它实际上仍然是优化的 完美(一个“额外的” mov 调用,因为我最初将其视为 8 字节 值,然后作为指针取消引用的 1 字节值)

call    __main
movl    $4, 44(%rsp)
movb    $2, 44(%rsp)
leaq    .LC0(%rip), %rcx
movl    44(%rsp), %eax
leal    1(%rax), %edx
call    printf

关于我的问题:

  1. 关于指针取消引用的编译器优化有多一致?在哪些情况下它会选择保守?

  2. 如果项目中的所有指针都使用 restrict 关键字声明,我是否可以相信它会像“根本没有使用任何指针”一样得到优化?

(假设没有volatile 情况)

Ps¹.: 我知道编译器通常做得很好,而且 担心帮助编译器进行较小优化的程序员是, 一般的,低效的(正如很多人在 stackoverflow 的回答中指出的那样 有关优化的问题)。不过我对这件事还是很好奇。

Ps².: gcc -O3 -S -c main.c 是用来生成汇编代码的命令

C 代码:(根据要求)

1:

#include <stdio.h>

int main (void)
{
    int a = 4;
    int *ap = &a;

    *ap = 0;
    a += 1;

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

2:

#include <stdio.h>

void change(int *p) {
    *p -= 2;
}

int main (void)
{
    int a = 4;
    int *ap = &a;

    *ap = 0;
    change(ap);
    a += 1;

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

3:

#include <stdio.h>

void change(void *p) {
    *((char*)p) += 2;
}

int main (void)
{
    int a = 4;
    void *ap = (void*) &a;

    *((char*)(ap)) = 0;
    change(ap);
    a += 1;

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

最佳答案

LLVM 和 GCC 都发出静态单赋值形式的代码作为优化分析的一部分。 SSA 代码的一个有用属性是它可以精确地显示赋值的影响流——也就是说,它知道什么赋值导致其他赋值,因此可以检测哪些值可以影响所有其他值。

第一个影响链看起来像

a1 -> 常量(0) -> ap -> a2

第二个: a1 -> 常量(0) -> ap -> p -> a2

第三个与第二个非常相似。 (抱歉,这个符号几乎是虚构的,但我希望它能说明我的观点。)

因为要证明 a 对 ap 的影响是确定性的相当简单,所以可以随意取消对“早期”的引用并将指令合并为一个(尽管在前两种情况下这不是最准确的陈述因为常量会覆盖原始引用并让编译器证明原始赋值不会流到代码末尾。

使编译器对取消引用更加保守将涉及变得足够复杂以逃避编译器的理解(我认为这在静态程序中很困难)或者更有可能导致编译器在 SSA 过程中调用 phi 函数(在外行人看来项,使分配受到多个先前分配的影响)以不确定的方式。

restrict 关键字的目的是向编译器提示两个指针不同。如果生成该指针的代码仍然具有不确定的源(例如,如果运行时创建的数据影响了对取消引用的指针值的选择,这不会限制在运行时取消引用的使用 - 我认为如果序列化指针是从外部源发送到程序中的吗?)

关于c - 如果有的话,编译器什么时候会在指针取消引用优化方面保持保守?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31527405/

相关文章:

c - *(++ptr) 是什么样的运算符?

python - 从 c 字符数组创建 PyString 而不复制

c - void 指针及其对 void 数据类型的赋值

c++ - 与 [[gnu::pure]] 一起使用的 Meyers 单例是否有 UB?

c - _dl_sysinfo_int80 的用途是什么?

无法在 GCC crunchbang 中编译 x86

c - 将字符串输入多维字符数组?

c - fts_children() 不工作

c - 数组符号衰减为指针符号 - 仅适用于函数参数?

ios - 基本编程概念: when to initialize new string versus just creating new variable