ZHCU881D May 2020 – May 2024
如果 C7100 和 C7120 器件上使用了 --auto_stream=no_saving 选项,或 C7504 和更高版本的器件上使用了 --auto_stream=saving 选项,编译器可以自动使用流引擎 (SE) 和/或流地址生成器 (SA)。
如果节 3.3.2 中的 weighted_vector_sum_v3.cpp 示例是使用 --auto_stream=no_saving 选项编译的,则会生成以下软件流水线信息块。(本例中生成的汇编适用于 C7100。)
;* SOFTWARE PIPELINE INFORMATION
;*
;* Loop found in file : weighted_vector_sum_v2.cpp
;* Loop source line : 7
;* Loop opening brace source line : 7
;* Loop closing brace source line : 9
;* Loop Unroll Multiple : 32x
;* Known Minimum Iteration Count : 32
;* Known Max Iteration Count Factor : 1
;* Loop Carried Dependency Bound(^) : 2
;* Unpartitioned Resource Bound : 2
;* Partitioned Resource Bound : 2 (pre-sched)
;*
;* Searching for software pipeline schedule at ...
;* ii = 2 Schedule found with 4 iterations in parallel. . .
;*----------------------------------------------------------------------------*
;* SINGLE SCHEDULED ITERATION
;*
;* ||$C$C36||:
;* 0 TICK ; [A_U]
;* 1 VMPYWW .N2 VBM1,SE0++,VBL0 ; [B_N2] |8| ^
;* || VMPYWW .M2 VBM0,SE1++,VBL1 ; [B_M2] |8| ^
;* 2 VMPYWW .N2 VBM1,SE0++,VBL0 ; [B_N2] |8| ^
;* || VMPYWW .M2 VBM0,SE1++,VBL1 ; [B_M2] |8| ^
;* 3 NOP 0x2 ; [A_B]
;* 5 VADDW .L2 VBL1,VBL0,VB0 ; [B_L2] |8|
;* 6 VST16W .D2 VB0,*D0(0) ; [A_D2] |8|
;* || VADDW .L2 VBL1,VBL0,VB0 ; [B_L2] |8|
;* 7 VST16W .D2 VB0,*D0(64) ; [A_D2] |8| [C0]
;* || ADDD .D1 D0,0x80,D0 ; [A_D1] |7| [C1]
;* || BNL .B1 ||$C$C36|| ; [A_B] |7|
;* 8 ; BRANCHCC OCCURS {||$C$C36||} ; [] |7|
在本例中,编译器使用 SE0 和 SE1 来替换之前设置了更低 ii 下限 4 的负载。通过使用 SE 执行这些负载,可以实现 2 ii。要使用上述示例中的 SE,编译器必须配置和打开它们。配置和打开操作显示在由循环之前的 --src_interlist 选项添加的注释中:
;*** ----------------------- S$1 = __internal_SE_TEMPLATE_1_i_1_i_d_i_d_i_d_i_d_i_d_2_4;
;*** ----------------------- S$1.ICNT0 = C$5 = (unsigned)(n+15&0xfffffff0);
;*** ----------------------- __se_open_V0_U32_O(*__se_mem((packed void *)a), 0, S$1);
;*** ----------------------- S$3 = __internal_SE_TEMPLATE_1_i_1_i_d_i_d_i_d_i_d_i_d_2_4;
;*** ----------------------- S$3.ICNT0 = C$5;
;*** ----------------------- __se_open_V0_U32_O(*__se_mem((packed void *)b), 1, S$3);
默认情况下,编译器仅在使用 SE 或 SA 看起来有利可图且合法时才使用它们。
就盈利能力而言,一个关键的考虑因素是使用 SE 或 SA 会带来处理开销;编译器未必知道此开销有利可图。在示例中,MUST_ITERATE pragma 指示最小迭代计数为 1024,这使编译器相信使用 SE 或 SA 可能有利可图,因此编译器执行转换。如果编译器未使用 SE 或 SA,而您希望编译器使用它们,则使用 MUST_ITERATE 或 PROB_ITERATE pragma 指示迭代次数会有所帮助。
出于合法性的考虑,不使用 SE 或 SA 的大多数原因与是否需要寻址模式可始终映射到 SE 或 SA 相关。这些原因包括但不限于:
i
和 icnt
是 64 位类型时,for (i = 0; i < icnt; i++)
中会发生这种情况。dim
是 64 位类型时,data_in[i*dim]
中会发生这种情况。i
或 dim
是 64 位类型时,data_in[i*dim]
中会发生这种情况。int16_ptr[i]
中,当 int16_ptr
为 int16 *
且 i
为 int
时,最大范围是 INT_MIN*16 个元素到 INT_MAX*16 个元素。这些都是非典型情况,在实践中不太可能发生。要允许编译器忽略它们,请使用 --assume_addresses_ok_for_stream 选项。
如果使用 SE 或 SA 在实践中没有优势,您可以使用 FUNCTION_OPTIONS pragma 覆盖单个函数的 --auto_stream 和/或 --assume_addresses_ok_for_stream 选项。
如果代码在函数中显式使用 SE 或 SA,则编译器不会选择使用 SE 或 SA 进行优化。在这种情况下,编译器会假定代码使用该函数内的 SE 和 SA 处理优化的所有方面。
有关自动使用 SE 和 SA 以及相关编译器选项的详细信息,请参见 C7000 C/C++编译器用户指南 (SPRUIG8)。