这部分有些过时了,可以不看。TI local FAE开发了一个很好的profiling工具,采用function hook的办法可以profiling函数的执行次数和消耗的cycle数。需要6.1版本以上的编译器才能支持。
2.4 Refining C/C++ Code
2.4.1 Using Intrinsics
14
介绍使用intrinsic 优化代码,有intrinsic的列表。不过仅限于C64+,其实除了load/store的操作之外,intrinsic基本和DSP指令是一一对应的,所以可以参考TMS320C66x DSP CPU and Instruction Set Reference Guide sprugh7.pdf,较全的intrinsic可以在..compilerc6000includec6x.h中找到,
2.4.3.2 Eliminating Redundant Loops, 在循环的最少循环次数未知时,编译器会生冗余的循环。介绍了什么是冗余循环以及怎样消除它。
2.4.3.3 Communicating Trip-Count Information to the Compiler
2.4.3.4 Loop Unrolling
2.4.3.5 Speculative Execution (?mh option)
2.4.3.6 What Disqualifies a Loop from Being Software-Pipelined
3 Compiler Optimization Tutorial
3.1 Introduction: Simple C Tuning
3.2 Lesson 1: Loop Carry Path From Memory Pointers
a) If a particular argument in a function always has the same value, the compiler replaces the argument with the value and passes the value instead of the argument.
b) If a return value of a function is never used, the compiler deletes the return code in the function.
c) If a function is not called, directly or indirectly, the compiler removes the function.
d) Also, using the −pm option can lead to better schedules for your loops. If the number of iterations of a loop is determined by a value passed into the function, and the compiler can determine what that value is from the caller, then the compiler will have more information about the minimum trip count of the loop leading to a better resulting schedule.
4 Additional Tuning Techniques for C66x Software-Pipelined Loops .
4.1 Reducing Register Pressure in the TMS320C66x .
14
结合MMSE equalizer的例子介绍了怎样解决寄存器压力过大的问题。C66的寄存器个数和C64+相同,在使用了占用大量寄存器的指令(例如矩阵乘和更宽的SIMD)以后很容易出现寄存器压力过大的问题。所谓寄存器压力过大就是由于循环中有大量临时变量。编译器没有足够的寄存器分配给这些临时变量,编译器不得不减少展开的次数或者把部分局部变量存在stack中,这都会导致循环效率的降低。减少寄存器压力过大的主要方法是掺杂使用4way SIMD指令和2 way SIMD指令。不过这又会影响A B datapath的balance,所以要找到最好的平衡点需要不断尝试。这里还介绍了使用DMV指令消除寄存器压力过大的方法。不过这种用法太讲究。需要对pipeline做细致的分析。只有精益求精抠一两个cycle的时候才会用到。
4.2 C66x Limitation on Common Sub Expressions (CSE) .
这个文档1~4章的内容在TMS320C6000 Programmer’s Guide中都有介绍,第五章可以着重看看。介绍了Optimizing Control Code的方法。所谓的控制代码就是循环比较少,没有密集运算的代码。或者是有循环,但是循环内部有大量结构体域的操作或者有大量判断的代码。这样的代码通常因为dependency的原因编译器不能优化的很好。需要人工做些代码调整。
章节
pages
导读
5.1 Restrict Qualifying Pointers Embedded in Structures
6
在结构体中restrict-qualification是不能传递的。假设有结构体
typedef struct[
short * data1;
short * data2;
]s;
即使我们声明s结构体指针为restrict-qualified,但是结构体中的指针s->data1, s->data2p仍然是non-qualified。
解决的办法是代码中定义局部的restrict-qualified指针。把结构体内部的指针赋值给这些局部指针,用局部指针来访问数组
例如: 下面定义了局部指针ptr1和ptr2。把结构体内部指针s->data1和s->data2赋值给它们。后续的运算使用指针ptr1和ptr2来访问数据。
short * restrict ptr1;
short * restrict ptr2;
ptr1 = s->data1;
ptr2 = s->data2;
5.2 Optimizing “If” Statements
在循环中如果有复杂的if/else分支会导致Disqualified loop,编译器不能产生software pipeline。这一张通过7个小节case by case的介绍了怎样拆解简化循环中的条件分支:
5.2.1 If-Conversion
5.2.2 “If” Statement Reduction When No “Else” Block Exists
5.2.3 “If” Statement Elimination
5.2.4 “If” Statement Elimination By Use of Intrinsics
5.2.5 “If” Statement Reduction Via Common Code Consolidation