[EXT_EP-11874] assignment to a bit field mistakenly overwrites entire bit field structure Created: 09/Aug/24  Updated: 24/Feb/25

Status: Accepted
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: Unresolved Votes: 0
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Product: Code Generation Tools
Internal ID: CODEGEN-12762
Forum URL: https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/171/t/1398207
Found In Release: C2000_25.3.0.LTS*
C7000_NEXT
C2000_18.1.0.LTS
C6000_8.3.0
MSP430_20.2.0.LTS
C7000_2.1.0.LTS
C2000_22.6.1.LTS
ARM_18.12.0.LTS
MSP430_21.6.0.LTS
C7000_5.0.0.LTS
C2000_21.6.0.LTS
PRU_2.3.0
C7000_3.1.0.LTS
PRU_2.2.0
C7000_6.0.0.LTS*
ARM_20.2.0.LTS
C7000_4.1.0.LTS
C2000_20.2.0.LTS
C2000_15.12.0.LTS
C2000_6.4.0
PRU_2.4.0*
C2000_18.12.0.LTS
Fix In Release: C2000_25.3.0.LTS*
C2000_22.6.3.LTS
C2000_21.6.2.LTS*
Affected Platform/Device: default
Workaround: Use --opt_level=off,0

 Description   

The compiler incorrectly optimizes an assignment to a bit field where

left hand side is a bit field with the same size as "int", and is within a struct with multiple bit fields
right hand side is either "int" or cast to "int"
and the generated code incorrectly does not mask the right hand side before assigning over the entire struct.

Above occurs for --opt_level=1,2,3,4 (and not --opt_level=off,0)

NOTE: below example is for C28 which has 16bit "int", however the same bug can occur on architectures with 32bit "int" and 32bit bit fields with 64bit double assign cast through int32_t.

NOTE: below test case only triggers the bug with little endian due to the sizes of types being assigned, however, the bug occurs for both big/little endian.
The attached source file has these lines ...

struct

{ uint32_t a:16; uint32_t b:16; }

instance;

float getA()

{ return -10.f; }

int16_t getB()

{ return 10; }

void fxn()

{ instance.b = getB(); instance.a = (int16_t)getA(); }

Build it ...

% cl2000 -@options.txt -s file.c
Inspect the assembly code in file.asm. These are the comments added by the compiler.

;*** 14 ------ *&instance &= 0xffffuL;
;*** 14 ------ *&instance |= (unsigned long)getB()<<16;
;*** 15 ------ *&instance &= 0xffff0000uL;
;*** 15 ------ *&instance |= (unsigned long)(int)getA();
The second |= expression is wrong. It is missing a 16bit mask.
It instead overwrites the entire structure.

The correct code generated by the compiler is shown below with missing mask for line 15:

;*** 14 ------- *&instance &= 0xffffuL;
;*** 14 ------- *&instance |= (unsigned long)getB()<<16;
;*** 15 ------- *&instance &= 0xffff0000uL;
;*** 15 ------- *&instance |= (unsigned long)(int)getA()&0xffffuL;


Generated at Thu Apr 10 18:52:26 CDT 2025 using Jira 9.12.17#9120017-sha1:aba4002bcd633f188b6a4bb5dd8a0e1f20b79ee4.