-
Type:
Bug
-
Resolution: Fixed
-
Priority:
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.