[EXT_EP-11922] Multiplication assignment operation, int32 *= (uint16_t)int16, incorrectly loses the cast to uint16_t during optimization Created: 19/Aug/24  Updated: 15/Oct/25  Resolved: 15/Oct/25

Status: Fixed
Project: Embedded Software & Tools
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Medium
Reporter: TI User Assignee: TI User
Resolution: Fixed Votes: 0
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Product: Code Generation Tools
Internal ID: CODEGEN-12778
Forum URL: https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/171/t/1401778
Found In Release: C2000_25.3.0.LTS*
C2000_22.6.0.LTS
C2000_18.1.7.LTS
C2000_21.6.0.LTS
C2000_18.12.3.LTS
C2000_20.2.0.LTS
Fix In Release: C2000_25.3.0.LTS*
C2000_21.6.2.LTS*
C2000_22.6.4.LTS*
Affected Platform/Device: default
Workaround: Use --opt_level=off or 0

 Description   

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.


Generated at Sat Dec 13 11:34:58 CST 2025 using Jira 10.3.7#10030007-sha1:a563685562f94d165eb4e158cfb2a142338d8c54.