限制条件 - 2023.2 简体中文

AI 引擎内核与计算图编程指南 (UG1079)

Document ID
UG1079
Release Date
2023-12-04
Version
2023.2 简体中文

C 语言标准可提供特定指针限定符 __restrict,此限定符旨在通过显式声明任意指针引用与所有其他变量之间的数据独立性,从而开展更激进的编译器最优化。例如:

int a; // global variable
void foo(int* __restrict p, int* q)
{
  for (...) { ... *p += a + *q; ...}
}

现在 foo 分析可在已知 *p 所表示的对象与 *qa 并不相同的前提下继续操作。因此,a*q 现在可在循环之前加载一次。

当前,编译器前端并不会消除对相同阵列进行不同访问之间所存在的任何歧义。因此更新阵列中的某个元素时,假定整个阵列均已更改该值。__restrict 限定符可用于覆盖此保守假定。如果要获取对同一阵列的多个独立指针,那么此限定符很有用。

void foo(int A[])
{
  int* __restrict rA = A; // force independent access
  for (int i = ...)
  rA[i] = ... A[i];
}

在此示例中,__restrict 限定符允许对循环进行软件流水打拍,在上一个阵列元素仍必须完成存储的同时,下一个阵列的元素可能已加载。为了尽可能扩大 __restrict 限定符的影响,默认情况下,编译器前端会在初始化器中插入 chess_copy 运算,编写方式如下:

int* __restrict rA = chess_copy(A);

为了使优化器中的两个指针之间保持有所差别(例如,无公共子表达式消除),这是必需的。对于 aiecompiler 前端,可通过 -mllvm -chess-implicit-chess_copy=false 选项来禁用此行为。因此,chess_copy 会创建两个指针,而 __restrict 则会告知编译器不考量通过这些指针的存储/加载之间的任何相互依赖关系。对于具有局部作用域的 __restrict 指针,仅在 __restrict 指针生存期内,相互独立性的假设才有效。

衍生自 __restrict 指针的指针(例如,rA+1 或者穿越指针内部调用)会保留此限制,即这些指针被视为指向相同的受限存储区域。

注释: 如需了解有关 chess_copy 的详细信息,请参阅 AI 引擎专区中提供的ASIP 程序员 Chess 编译器用户手册