gpt4 book ai didi

c - 在 C 中使用限制关键字的规则?

转载 作者:IT王子 更新时间:2023-10-28 23:28:23 27 4
gpt4 key购买 nike

我试图了解何时以及何时不使用 C 中的 restrict 关键字,以及在什么情况下它提供了切实的好处。

读完“Demystifying The Restrict Keyword”(它提供了一些使用经验法则)后,我的印象是,当一个函数被传递指针时,它必须考虑到指向的数据可能重叠的可能性(别名)以及传递给函数的任何其他参数。给定一个函数:

foo(int *a, int *b, int *c, int n) {
for (int i = 0; i<n; ++i) {
b[i] = b[i] + c[i];
a[i] = a[i] + b[i] * c[i];
}
}

编译器必须在第二个表达式中重新加载 c,因为可能 bc 指向同一个位置。出于同样的原因,它还必须等待 b 被存储,然后才能加载 a。然后它必须等待 a 被存储,并且必须在下一个循环开始时重新加载 bc。如果你这样调用函数:

int a[N];
foo(a, a, a, N);

然后你就会明白为什么编译器必须这样做。使用 restrict 有效地告诉编译器你永远不会这样做,以便它可以丢弃 c 的冗余负载并在 之前加载 a >b 被存储。

In a different SO post, Nils Pipenbrinck, provides a working example of this scenario demonstrating the performance benefit.

到目前为止,我已经收集到在传递给不会被内联的函数的指针上使用 restrict 是个好主意。显然,如果代码被内联,编译器可以确定指针不重叠。

现在我的事情开始变得模糊了。

在 Ulrich Drepper 的论文“What every programmer should know about memory”中,他声明“除非使用了限制,否则所有指针访问都是潜在的别名来源”,并且他给出了一个子矩阵乘法的具体代码示例,其中他使用限制

但是,当我使用或不使用 restrict 编译他的示例代码时,我在两种情况下都会得到相同的二进制文件。我正在使用 gcc 版本 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

我在下面的代码中无法弄清楚的是是否需要重写以更广泛地使用 restrict,或者 GCC 中的别名分析是否非常好,以至于能够弄清楚没有一个参数相互别名。 出于纯粹的教育目的,我如何才能在此代码中使用或不使用 restrict - 为什么?

对于 restrict 编译时:

gcc -DCLS=$(getconf LEVEL1_DCACHE_LINESIZE) -DUSE_RESTRICT -Wextra -std=c99 -O3 matrixMul.c -o matrixMul

只需删除 -DUSE_RESTRICT 即可不使用 restrict

#include <stdlib.h>
#include <stdio.h>
#include <emmintrin.h>

#ifdef USE_RESTRICT
#else
#define restrict
#endif

#define N 1000
double _res[N][N] __attribute__ ((aligned (64)));
double _mul1[N][N] __attribute__ ((aligned (64)))
= { [0 ... (N-1)]
= { [0 ... (N-1)] = 1.1f }};
double _mul2[N][N] __attribute__ ((aligned (64)))
= { [0 ... (N-1)]
= { [0 ... (N-1)] = 2.2f }};

#define SM (CLS / sizeof (double))

void mm(double (* restrict res)[N], double (* restrict mul1)[N],
double (* restrict mul2)[N]) __attribute__ ((noinline));

void mm(double (* restrict res)[N], double (* restrict mul1)[N],
double (* restrict mul2)[N])
{
int i, i2, j, j2, k, k2;
double *restrict rres;
double *restrict rmul1;
double *restrict rmul2;

for (i = 0; i < N; i += SM)
for (j = 0; j < N; j += SM)
for (k = 0; k < N; k += SM)
for (i2 = 0, rres = &res[i][j],
rmul1 = &mul1[i][k]; i2 < SM;
++i2, rres += N, rmul1 += N)
for (k2 = 0, rmul2 = &mul2[k][j];
k2 < SM; ++k2, rmul2 += N)
for (j2 = 0; j2 < SM; ++j2)
rres[j2] += rmul1[k2] * rmul2[j2];
}

int main (void)
{

mm(_res, _mul1, _mul2);

return 0;
}

最佳答案

这是对代码优化器的提示。使用 restrict 可以确保它可以将指针变量存储在 CPU 寄存器中,而不必将指针值的更新刷新到内存中,以便更新别名。

它是否利用它在很大程度上取决于优化器和 CPU 的实现细节。代码优化器已经在检测非锯齿方面投入了大量资金,因为它是如此重要的优化。在您的代码中检测到它应该没有问题。

关于c - 在 C 中使用限制关键字的规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2005473/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com