【问题标题】:c99 __restrict and compiler optimizationc99 __restrict 和编译器优化
【发布时间】:2012-06-08 01:21:46
【问题描述】:
typedef struct {
    void * field1;
} s1;

void func1(void) {
    s1 my_s1;
    s1 * __restrict my_s1_ptr = &my_s1;
    *((int*)((char*)my_s1_ptr->field1 + 4))  = 0;
    *((int*)((char*)my_s1_ptr->field1 + 8))  = 1;
    *((int*)((char*)my_s1_ptr->field1 + 12)) = 2;
    *((int*)((char*)my_s1_ptr->field1 + 16)) = 3;
}

似乎对于 Intel 编译器 11.1 版和 gcc 4.6 版,编译器会为最后 4 个语句中的每一个重新加载 my_s1_ptr->field1。我对 __restrict 的理解会告诉我最后 3 个负载应该是多余的并且可以被消除。是的,我知道代码很奇怪,但它的结构是这样的。我只是希望能够让编译器消除冗余负载。知道如何说服它这样做吗?

【问题讨论】:

  • 你编译优化了吗?为什么你使用__restrict而不是restrict,这是一个C99关键字?
  • 我确实进行了优化编译,__restrict 与 restrict 没有区别。
  • 我只是在指向字段的指针而不是指向结构的指针上尝试了几种变体,它没有改变任何东西。在实际代码中,可能有多个指针指向 field1 指向的内容,因此将限制添加到 field1 是无效的(但即使我尝试过它也没有消除负载)。如果我将 field1 复制到一个限制局部变量指针,那么冗余负载将被消除,但就像我说的那样,这违反了程序的语义。
  • AFAIK, restrict 并不总是优化。它“可能允许编译器”执行优化。编译器不需要执行这些优化。无论如何,我觉得很奇怪,你的情况不是这样。
  • 你的例子正确吗?当你取消引用它时,field1 没有指向任何东西......其次,由于 my_s1_ptr->field1 不受限制,它重新加载该指针不是正常的,还是你的意思是它重新加载 my_s1_ptr?

标签: c optimization compiler-construction c99 restrict-qualifier


【解决方案1】:

s1 * __restrict 表示这是指向特定s1 的唯一指针,因此该类型没有别名。这并不意味着不会有其他指针类型的别名,例如void*、int* 或char*。

使用char* 对编译器来说尤其麻烦,因为char* 被明确允许用于访问其他类型的字节。 (char也是字节的意思,可以用来访问其他类型的底层内存)。

如果编译器不能证明你的赋值永远不会改变指向的东西,它每次都必须重新加载指针。例如,它怎么知道void* field1 没有指向自己?


如果没有所有演员表,这样的事情难道不可行吗?

int* p = my_s1.field1;
p[1] = 0;
p[2] = 1;
p[3] = 2;
p[4] = 3;

假设 int 是 4 个字节,而 field1 实际上指向一个数组。

【讨论】:

  • "char 也表示字节" -> 编译器是否必须注意任何char,或者只是unsigned char? (不确定,这就是我问的原因。:P)
  • 我们主要使用unsigned char,因为那时我们知道签名,但是普通的char可能是一样的,也可以用来访问内存(无论是否实际签名)。
  • “s1 * __restrict 表示这是指向特定s1 的唯一指针”:我不知道__restrict,但例如C99 的restrict 并非如此在void *memcpy(void * restrict s1,const void * restrict s2,size_t n);。第 6.7.3.1 节定义了基于对象的指针表达式的概念,并且没有提供指针转换(允许将 memcpy 原样原型化)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 2011-11-07
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 2014-02-21
  • 2011-08-24
相关资源
最近更新 更多