NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
C6000 Compiler Obscure Restrict Bug
Contents
Introduction[edit]
The C6000 C Compiler has a bug related to the use of restrict pointers inside loops. This bug rarely affects generated code in practice. This article describes this bug, and what to do about it.
Bug Description[edit]
Consider this code fragment.
<syntaxhighlight lang="c"> // Almost sorts, but not really void almost_sorts(int * restrict base, int length) {
int i;
for (i = 0; i < length-1; i++) { if (base[i] < base[i+1]) { int tmp; int * restrict p1 = &base[i]; int * restrict p2 = &base[i+1];
tmp = *p1; *p1 = *p2; *p2 = tmp; } }
} </syntaxhighlight>
This is correct usage of the restrict keyword. During execution of that innermost block where they are declared, the pointers p1 and p2 never point to the same memory address. The article Restrict Type Qualifier has more detail on restrict.
But recall that the C6000 compiler, to maximize performance, may overlap loop iterations using a technique called software pipelining. Details can be found in Hand-Tuning Loops and Control Code on the TMS320C6000 tidoc:spra666, in the first part of section 4. Thus, p2 of loop iteration N and p1 of loop iteration N+1 could point to the same memory location. Is this correct usage of the restrict keyword? Yes. It is up to the compiler to detect this possible aliasing and schedule the loop accordingly. Within a loop iteration, no aliasing is possible. Across loop iterations, aliasing is possible.
For this example the compiler correctly assumes there is no aliasing within a loop iteration. However, the compiler does not account for possible aliasing among loop iterations. Thus the compiler may emit code which executes incorrectly.
Restrict in Loop Usually Arises from Function Inlining[edit]
Actual instances of this bug causing incorrect code to be generated are quite rare. That is because of the precise manner in which the restrict must be used to cause the problem. The example above is written to clearly illustrate the problem. Here is a code fragment which shows how the problem more typically appears.
<syntaxhighlight lang="c">
do { changed = FALSE; for (i=0; i < length-1; i++) { if(ary[i].size < ary[i+1].size) { swap(&ary[i], &ary[i+1]); // gets inlined changed = TRUE; } } } while (changed);
// ...
static inline void swap (struct sss * restrict p1,
struct sss * restrict p2)
{
// swap contents of the two structs
} </syntaxhighlight>
Some of the fields in certain structs in the array get corrupted. Note how the restrict does not appear in the main part of the example, but comes in because the compiler inlines the function swap.
Workaround[edit]
Workaround this problem by not using the restrict keyword in the problem loop. This makes the performance of the loop worse; sometimes much worse. But at least the impact is limited to one loop.
Version Information[edit]
This bug is present in all 6.0.x and 6.1.x versions of the compiler. It is fixed in versions 7.0.x and later.