This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28388D: Possible compiler bug during optimization of inline function

Part Number: TMS320F28388D

Dear TI experts, 

after some time spent debugging my source code, I have a reasonable suspicion that CL2000 compiler might have a bug in optimization of inline functions. 

I will do my best to describe this strange behaviour and I hope that You can confirm or oppose my suspicions.

It is important to note that this is a very specific case, and any changes in source code will most likely make the bug "invisible", i.e. everything will seem to work fine.

Nevertheless, this does not deny the existence of a bug, and I would like to address this problem with a hope that it will be fixed in some future releases. 

I have attached a source files needed for replicating discussed behaviour, and I will try to explain the logic behind specific code snippets. 

Firstly, in C source code, we have a call to an inline function that reads consecutive memory locations from an external peripheral interface (EMIF). (FPGA_values.c, line 74) 

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* in header file */
inline static void ElFunc_MEMRD8_L(int32_t address, uint16_t n1, uint16_t n2, uint16_t n3, uint16_t n4, uint16_t n5, uint16_t n6, uint16_t n7, uint16_t n8, int32_t* value1, int32_t* value2, int32_t* value3, int32_t* value4, int32_t* value5, int32_t* value6, int32_t* value7, int32_t* value8){
*value1 = (MEMRD_HWREG_L(address) << n1);
*value2 = (MEMRD_HWREG_L(address + 1 * MEMRD_ADDR_L) << n2);
*value3 = (MEMRD_HWREG_L(address + 2 * MEMRD_ADDR_L) << n3);
*value4 = (MEMRD_HWREG_L(address + 3 * MEMRD_ADDR_L) << n4);
*value5 = (MEMRD_HWREG_L(address + 4 * MEMRD_ADDR_L) << n5);
*value6 = (MEMRD_HWREG_L(address + 5 * MEMRD_ADDR_L) << n6);
*value7 = (MEMRD_HWREG_L(address + 6 * MEMRD_ADDR_L) << n7);
*value8 = (MEMRD_HWREG_L(address + 7 * MEMRD_ADDR_L) << n8);
return;
}
/* in .c source file */
ElFunc_MEMRD8_L(FPGA_ADC1_A0_LSW, 0, 0, 0, 0, 0, 0, 0, 0, &A0_LSW, &A1_LSW, &B0_LSW, &B1_LSW, &C0_LSW, &C1_LSW, &D0_LSW, &D1_LSW);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Some lines after that function, we have another inline function that only casts int32_t variable to float32_t, as follows: (FPGA_values.c, line 79) 

Fullscreen
1
2
3
4
5
6
7
8
9
10
/* in header file */
inline static float32_t ElFunc_INT32FLP(int32_t input){
return (float32_t)input;
}
/* in .c source file */
...
AIN04_FLP = ElFunc_INT32FLP(B1_LSW);
...
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 

Now, the problem happens when optimization O2 is used. 

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
506 .dwpsn file "FPGA_values.h",line 45,column 5,is_stmt,isa 0
507 0000004a 8F38 MOVL XAR4,#3671270 ; [CPU_ARAU] |45|
0000004b 04E6
508 0000004c 8AC4 MOVL XAR4,*+XAR4[0] ; [CPU_ALU] |45|
509 0000004d A800! MOVL @||B1_LSW||,XAR4 ; [CPU_ALU] |45|
510 .dwpsn file "FPGA_values.h",line 34,column 3,is_stmt,isa 0
511 0000004e E2AF MOV32 R2H,*+XAR4[0] ; [CPU_FPU] |34|
0000004f 02C4
512 .dwpsn file "FPGA_values.h",line 46,column 5,is_stmt,isa 0
513 00000050 8F38 MOVL XAR4,#3671272 ; [CPU_ARAU] |46|
00000051 04E8
514 .dwpsn file "FPGA_values.h",line 34,column 3,is_stmt,isa 0
515 00000052 E689 I32TOF32 R2H,R2H ; [CPU_FPU] |34|
00000053 0012
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

In "FPGA_values.lst" file, on the line marked with 507 (line 581 in file) we can see that XAR4 is loaded with #3671270 (0x3804E6), and on the lines 508 and 509 (583 and 584 in file) we can see that the value from that memory location is stored in XAR4 and after that in @B1_LSW. That is exactly what we want. 

The problem lies in the next (FPU) instruction. On the line 511 (586 in file), the compiler thinks that the register XAR4 still has an address and tries to load register R2H with a value on that address. This assumption is completely wrong because at that point, register XAR4 does not contain an address any more, but a real value that was read on the line 508 (583 in file). Looking at the source code, the correct instruction would be something like MOV32 RH2, XAR4 or MOV32 RH2, @||B1_LSW||, or something along those lines. 

The rest of the code seems to run fine (casting RH2 register to float, etc.), but storing the wrong value in R2H register on the problematic line (511/file 584) can easily cause hard fault and NMI, and of course, gives wrong results. 

In file CL2000_TMS320F28388D.bat, You can see compiler options (I've tried versions 22.6.0 and 22.6.1, but the results are the same). You can also use this script to compile the source file. 

I would like to add that this test case is a result of manually adapted software generated C code (hence the "weird" coding standard). We use our graphical programming software that generates a C source files, and that is the main reason why inline functions (and optimizations) are essential for us. 

Looking forward to hearing from You, 

Sandro Margeta

compiler_bug_testcase.zip

  • Hello,

    I have brought this thread to the attention of the compiler experts. They should be getting back to you later today.

    Thanks

    ki

  • Thank you for notifying us of this issue, and for supplying a test case.  I am able to reproduce the same behavior.  I filed the entry EXT_EP-11686 to have this investigated.  You are welcome to follow it with that link.

    Thanks and regards,

    -George