ZHCU881C May   2020  – December 2023

 

  1.   1
  2.   请先阅读
    1.     关于本手册
    2.     相关文档
    3.     商标
  3. 2引言
    1. 2.1 C7000 数字信号处理器 CPU 架构概述
    2. 2.2 C7000 分离式数据路径和功能单元
  4. 3C7000 C/C++ 编译器选项
    1. 3.1 概述
    2. 3.2 为性能选择编译器选项
    3. 3.3 了解编译器优化
      1. 3.3.1 软件流水线
      2. 3.3.2 矢量化和矢量谓词
      3. 3.3.3 自动使用流引擎和流地址生成器
      4. 3.3.4 循环折叠和循环合并
      5. 3.3.5 自动内联
      6. 3.3.6 if 转换
  5. 4基本代码优化
    1. 4.1  迭代计数器和限制的有符号类型
    2. 4.2  浮点除法
    3. 4.3  循环携带依赖和 restrict (限制)关键字
      1. 4.3.1 循环携带依赖
      2. 4.3.2 restrict (限制)关键字
      3. 4.3.3 运行时别名消歧
    4. 4.4  函数调用和内联
    5. 4.5  MUST_ITERATE 和 PROB_ITERATE Pragma 与属性
    6. 4.6  if 语句和嵌套的 if 语句
    7. 4.7  内在函数
    8. 4.8  矢量类型
    9. 4.9  待使用和避免的 C++ 特性
    10. 4.10 流引擎
    11. 4.11 流地址生成器
    12. 4.12 优化库
    13. 4.13 存储器优化
  6. 5了解汇编注释块
    1. 5.1 软件流水线处理阶段
    2. 5.2 软件流水线信息注释块
      1. 5.2.1 循环和迭代计数信息
      2. 5.2.2 依赖和资源限制
      3. 5.2.3 启动间隔 (ii) 和迭代
      4. 5.2.4 常量扩展
      5. 5.2.5 使用的资源和寄存器表
      6. 5.2.6 阶段折叠
      7. 5.2.7 存储器组冲突
      8. 5.2.8 循环持续时间公式
    3. 5.3 单个调度迭代注释块
    4. 5.4 识别流水线故障和性能问题
      1. 5.4.1 阻止循环进行软件流水线作业的问题
      2. 5.4.2 软件流水线故障消息
      3. 5.4.3 性能问题
  7. 6修订历史记录

循环携带依赖

在进行软件流水线的某些情况下,编译器无法重叠循环的连续迭代以获得最佳性能。当编译器不能重叠循环的连续迭代时,性能则会受到影响:启动间隔(前述所述 ii)将大于预期间隔,并且同时使用的功能单元也很少。

几乎所有的情况下,这都是由于循环携带依赖造成的。循环携带依赖在一定程度上阻止了迭代 i+1 的执行与迭代 i 重叠。循环携带依赖限制 是软件流水线循环启动间隔的下限(因此也限制了软件流水线循环速度)。由于循环中的一组指令集存在排序约束(依赖性)周期,所以会出现循环携带依赖限制。在循环中的所有这些周期长度中,最大的循环携带依赖周期就是循环携带依赖限制。即使有大量的可用功能单元并行执行若干迭代,也会发生这种情况。

如果循环携带依赖限制大于分区资源限制,则循环携带依赖之一会减慢循环,因为启动间隔始终至少是分区资源限制和循环携带依赖限制中的最大者。

为了减少或消除有问题的循环携带依赖,必须确定周期,然后找到一种方法以缩短或打破该周期。

以下示例显示了循环携带依赖有问题的循环。

void weighted_sum(int * a, int * b, int * out,                                 
                  int weight_a, int weight_b, int n)                           
{                                                                              
    #pragma UNROLL(1)                                                          
    #pragma MUST_ITERATE(1024, ,32)                                            
    for (int i = 0; i < n; i++)                                                
    {                                                                          
        out[i] = a[i] * weight_a + b[i] * weight_b;                            
    }                                                                          
}

本例中编译器生成的汇编代码(如下所示)显示了在汇编代码的软件流水线信息部分中,循环携带依赖限制为 7 个周期。

;*----------------------------------------------------------------------------* 
;*   SOFTWARE PIPELINE INFORMATION
;*
;*      Loop found in file               : weighted_vector_sum_v3.cpp
;*      Loop source line                 : 10
;*      Loop opening brace source line   : 11
;*      Loop closing brace source line   : 13
;*      Known Minimum Iteration Count    : 1024                    
;*      Known Max Iteration Count Factor : 32
;*      Loop Carried Dependency Bound(^) : 12
;*      Unpartitioned Resource Bound     : 2
;*      Partitioned Resource Bound       : 2 (pre-sched)
;*
;*      Searching for software pipeline schedule at ...
;*         ii = 12 Schedule found with 2 iterations in parallel
. . .
;*----------------------------------------------------------------------------*
;*        SINGLE SCHEDULED ITERATION
;*
;*        ||$C$C51||:
;*   0              TICK                               ; [A_U] 
;*   1              LDW     .D2     *D1++(4),BM0      ; [A_D2] |12|  ^ 
;*     ||           LDW     .D1     *D2++(4),BM1      ; [A_D1] |12|  ^ 
;*   2              NOP     0x5     ; [A_B] 
;*   7              MPYWW   .M2     BM2,BM0,BL0       ; [B_M2] |12|  ^ 
;*     ||           MPYWW   .N2     BM3,BM1,BL1       ; [B_N2] |12|  ^ 
;*   8              NOP     0x3     ; [A_B] 
;*  11              ADDW    .L2     BL1,BL0,B0        ; [B_L2] |12|  ^ 
;*  12              STW     .D1X    B0,*D0++(4)       ; [A_D1] |12|  ^ 
;*     ||           BNL     .B1     ||$C$C51||        ; [A_B] |10| 
;*  13              ; BRANCHCC OCCURS {||$C$C51||}    ; [] |10| 
;*----------------------------------------------------------------------------*

软件流水线循环的最终软件流水线启动间隔至少是循环携带依赖限制和分区资源限制中的较大者。当循环携带依赖限制值大于分区资源限制值时,表示代码中存在可能需要解决的循环携带依赖限制问题。也就是说,当循环携带依赖限制大于分区资源限制时,如果消除了循环携带依赖限制,软件流水线循环可能会运行得更快。因此,在本例中,由于分区资源限制是 2,循环携带依赖限制是 12,所以此代码中存在应被调查的问题。

为了确定该问题,我们需要查看循环携带依赖中涉及的指令。这些指令在编译器生成的汇编文件的注释块中,以脱字符“^”标记这些指令。请注意,加载和存储指令是以插入符号标记的。由此可知,编译器认为连续迭代之间可能 存在循环携带依赖的关系。这可能是因为编译器无法证明存储指令正在写入与加载指令所加载的位置无关的存储器区域。在缺少有关指针、数组和地址访问模式的位置信息时,编译器必须假定连续迭代可从前一次迭代的存储位置加载。有关循环携带依赖及其识别方法的更多信息,请参阅手动调优 TMS320C6000 上的循环和控制代码 (SPRA666)。