-
Bug
-
Resolution: Unresolved
-
Medium
-
Code Generation Tools
-
CODEGEN-12778
-
-
-
default
-
Use --opt_level=off or 0
Multiplication assignment operation like below that assigns to a int32_t/uint32_t variable from either a int16_t variable which is then cast to uint16_t (or an uint16_t variable which is then cast to int16_t) will receive an invalid optimization that incorrectly eliminates the cast:
This C code:
var_int32_t/var_uint32_t *= (uint16_t)var_int16_t
is incorrectly converted to below:
var_int32_t/var_uint32_t *= var_int16_t
And this C code:
var_int32_t/var_uint32_t *= (int16_t)var_uint16_t
is incorrectly converted to below:
var_int32_t/var_uint32_t *= var_uint16_t
NOTE: below may also have the issue:
var_int32 = var_int32 * (uint16_t)var_int16_t
To see the issue in the generated assembly, use option --src_interlist and below C code:
vint32 *= (uint16_t)vint16;
Will have assembly with below optimizer comments showing the lack of cast to uint16_t:
;*** 10 -------------- vint32 *= vint16;
Original description:
The attached file has these lines ...
int16_t gv1_i16 = 0xC0; int16_t gv2_i16 = 0xC000; int32_t multiply_with_global() { int32_t lv1_i32; lv1_i32 = gv1_i16; lv1_i32 *= (uint16_t)gv2_i16; return lv1_i32; // incorrect: -3145728 }
Build it ...
% cl2000 -@options.txt file.c
Inspect the resulting assembly file. Ignore the debug directives. The key lines of assembly are:
_multiply_with_global: ;* AL assigned to _lv1_i32 ;*** 10 ----------------------- _lv1_i32 = gv1_i16; ;*** 11 ----------------------- _lv1_i32 *= gv2_i16; ;*** 12 ----------------------- return _lv1_i32; MOVW DP,#_gv1_i16 ; [CPU_ARAU] SETC SXM ; [CPU_ALU] MOVX TL,@_gv2_i16 ; [CPU_ALU] |11| MOV ACC,@_gv1_i16 ; [CPU_ALU] |10| IMPYL ACC,XT,ACC ; [CPU_ALU] |11| LRETR ; [CPU_FPU]
Note how a signed instruction is used to load gv1_i16. Because of the cast to uint16_t, that should be an unsigned load.