编译器版本:TI v22.6.1.LTS
我在写一段算法的时候发现开启编译器O2等级优化后,控制器的系数生成出错了。于是我编写了下面的一段代码来测试,其中输入参数w我给了1:
struct TEST_STRUCT
{
float f1;
float f2;
};
volatile struct TEST_STRUCT TEST[5];
void TEST_FCN(float w)
{
Uint16 Index;
float w_temp;
for( Index = 5 ; Index > 0 ; Index-- )
{
w_temp = w * ( Index * 2 - 1 );
TEST[Index - 1].f1 = w_temp;
}
}
开启O2后生成的汇编代码如下:
MOVB XAR6,#4 ; [CPU_ALU]
MOVL XAR4,#||TEST||+16 ; [CPU_ARAU]
MOVIZ R3H,#16656 ; [CPU_FPU]
.dwpsn file "../main.c",line 22,column 22,is_stmt,isa 0
RPTB ||$C$L2||,AR6 ; [CPU_ALU] |22|
; repeat block starts ; []
||$C$L1||:
MOVIZ R2H,#18303 ; [CPU_FPU] |22|
.dwpsn file "../main.c",line 25,column 9,is_stmt,isa 0
MPYF32 R1H,R0H,R3H ; [CPU_FPU] |25|
.dwpsn file "../main.c",line 22,column 22,is_stmt,isa 0
MOVXI R2H,#65024 ; [CPU_FPU] |22|
ADDF32 R3H,R3H,R2H ; [CPU_FPU] |22|
|| MOV32 *+XAR4[0],R1H ; [CPU_FPU] |25|
SUBB XAR4,#4 ; [CPU_ALU] |22|
; repeat block ends ; []
||$C$L2||:
$C$DW$11 .dwtag DW_TAG_TI_branch
.dwattr $C$DW$11, DW_AT_low_pc(0x00)
.dwattr $C$DW$11, DW_AT_TI_return
LRETR ; [CPU_ALU]
; return occurs ; []
问题就出在( Index * 2 - 1 )的优化上:编译器将( Index * 2 - 1 )固定为R3H寄存器,这样每次循环将R3H减去2即可。由于Index被声明称Uint16无符号整型,编译器给R2H赋值0x477ffe00(65534),想要通过R3H=R2H+R3H来进行等效减法。但RxH是浮点寄存器,编译器只能调用ADDF32来进行浮点加法,导致得出了错误的结果:

如果我将Index声明为int16,编译得出的汇编代码是正确的,结果也正确:

MOVB XAR6,#4 ; [CPU_ALU]
MOVL XAR4,#||TEST||+16 ; [CPU_ARAU]
MOVIZ R1H,#16656 ; [CPU_FPU]
.dwpsn file "../main.c",line 21,column 22,is_stmt,isa 0
RPTB ||$C$L2||,AR6 ; [CPU_ALU] |21|
; repeat block starts ; []
||$C$L1||:
.dwpsn file "../main.c",line 24,column 9,is_stmt,isa 0
MPYF32 R2H,R0H,R1H ; [CPU_FPU] |24|
.dwpsn file "../main.c",line 21,column 22,is_stmt,isa 0
ADDF32 R1H,R1H,#49152 ; [CPU_FPU] |21|
.dwpsn file "../main.c",line 24,column 9,is_stmt,isa 0
MOV32 *+XAR4[0],R2H ; [CPU_FPU] |24|
.dwpsn file "../main.c",line 21,column 22,is_stmt,isa 0
SUBB XAR4,#4 ; [CPU_ALU] |21|
NOP ; [CPU_ALU]
NOP ; [CPU_ALU]
; repeat block ends ; []
||$C$L2||:
$C$DW$11 .dwtag DW_TAG_TI_branch
.dwattr $C$DW$11, DW_AT_low_pc(0x00)
.dwattr $C$DW$11, DW_AT_TI_return
LRETR ; [CPU_ALU]
; return occurs ; []
可以看到此时( Index * 2 - 1 )被固定为R1H,生成的汇编指令为ADDF32 R1H,R1H,#49152,即R1H=R1H-2。
我在TMS320C28x Optimizing C/C++ Compiler手册中没找到相关的信息,不清楚这是不是一个编译器优化BUG。