Intel® FPGA SDK for OpenCL™ Pro Edition: 最佳实践实践指南

ID 683521
日期 9/26/2022
Public
文档目录

6.1.5. 移除由于对存储器阵列的访问而引起的循环依赖

在您的单个work-item内核中包含ivdep pragma,以置位对存储器阵列的访问从而避免导致循环携带依赖项。
编译过程中, Intel® FPGA SDK for OpenCL™ Offline Compiler创建硬件来确保加载和存储指令在依赖约束内运行。依赖项约束的实例,如依赖加载和存储指令必须按顺序执行。有ivdep pragma是为了指示离线编译器在内核代码中的pragma声明之后立即从循环内加载和存储指令之间删除这个额外的硬件。删除该额外硬件可能会降低逻辑利用率并降低单个work-item内核中II的值。

您可以向 ivdep pragma添加safelen(N)子句来提供有关循环依赖关系的更多信息。safelen(N)子句指定没有携带依赖项的循环的连续循环迭代的最大次数。例如,#pragma ivdep safelen(32)向编译器指示在可能引入带有依赖项的循环之前,循环最多有32次迭代。也就是说,虽然#pragma ivdep约定该循环的任何迭代之间没有隐式存储器依赖项,但#pragma safelen(32)约定可能依赖于该迭代,并且最靠近该迭代的那个迭代与该迭代之间相距32次迭代。

  • 如果循环内所有到存储器阵列的访问都不会导致循环携带依赖项,则请在以内核代码运行该循环之前添加行#pragma ivdep
    内核代码实例:
    // no loop-carried dependencies for A and B array accesses
    #pragma ivdep
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
  • 要指定对循环内特定存储器阵列的访问不会导致 循环携带依赖项,请在运行您内核代码中的该循环之前添加行#pragma ivdep array (array_name)

    ivdep pragma指定的阵列必须是局部或者专用存储器阵列,或者是指向专用存储器存储空间的指针变量。如果指定的阵列是一个指针,则ivdep pragma也适用于以指定指针的别名命名的所有阵列。

    ivdep pragma指定的阵列也可以是数组或者结构体的指针部分。

    内核代码实例:

    // No loop-carried dependencies for A array accesses
    // The offline compiler will insert hardware that reinforces dependency constraints for B
    #pragma ivdep array(A)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
    
    // No loop-carried dependencies for array A inside struct
    #pragma ivdep array(S.A)
    for (int i = 0; i < N; i++) {
        S.A[i] = S.A[i - X[i]];
    }
    
    // No loop-carried dependencies for array A inside the struct pointed by S
    #pragma ivdep array(S->X[2][3].A)
    for (int i = 0; i < N; i++) {
        S->X[2][3].A[i] = S.A[i - X[i]];
    }
    
    // No loop-carried dependencies for A and B because ptr aliases
    // with both arrays
    int *ptr = select ? A : B;
    #pragma ivdep array(ptr)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
    
    // No loop-carried dependencies for A because ptr only aliases with A
    int *ptr = &A[10];
    #pragma ivdep array(ptr)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }