-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Medium
-
Code Generation Tools
-
CODEGEN-15499
-
-
-
-
default
-
For the C28 compiler with EABI, the DP load insertion pass fails to emit
a DP load between accesses to static struct fields that span DP boundaries.
The issue, however, is due to earlier placement on the same data page for
instances of structs with flexible array members that have incorrectly
calculated struct size.
The struct size calculation ignores the size of the flexible array member.
Example
Below should be 11 words in size (12 with alignment), however
the compiler is not including the 7 words from the flexible array:
typedef struct myStr
{
int* next;
int id;
int size;
char buffer[];
} myStr_t, *myStrHandle;
static myStr_t q0 = { .buffer = { [6] = 0 }, };
Here's the generated assembly for above
.data .align 2 .elfsym ||q0||,SYM_SIZE(4) ||q0||: .bits 0,32 ; q0.next @ 0 .bits 0,16 ; q0.id @ 32 .bits 0,16 ; q0.size @ 48 .bits 0,16 ; q0[0] @ 64 .bits 0,16 ; q0[1] @ 80 .bits 0,16 ; q0[2] @ 96 .bits 0,16 ; q0[3] @ 112 .bits 0,16 ; q0[4] @ 128 .bits 0,16 ; q0[5] @ 144 .bits 0,16 ; q0[6] @ 160 .sblock ".data"
For the submitted test case, the .data section included several of above
struct instances, followed by several static struct instances for a struct
type that did not have flexible array members. The DP load insertion
pass incorrectly misses inserting a DP load for accessing the struct
at the end of the data page which should have actually been placed on
the next data page.
The issue requires below:
- EABI
- static structs with flexible array members
- enough additional static structs on the same data page such that
the incorrect struct size results in a struct being placed on
the same data page instead of the next data page
Here's an example showing a case in C and assembly where s4 is on
the wrong data page:
C code
typedef struct myStr
{
bq_size_t* next;
bq_size_t id;
bq_size_t size;
char buffer[];
} myStr_t, *myStrHandle;
typedef struct LogChannel
{
const logDestination_t destination;
logBufferHandle_t logBuffer;
myStrHandle readyQueue;
myStrHandle doneQueue;
} logChannel_t;
static myStr_t q0 = { .buffer = { [6] = 0 }, };
static myStr_t q1 = { .buffer = { [6] = 0 }, };
static myStr_t q2 = { .buffer = { [6] = 0 }, };
static logChannel_t s0 = { .readyQueue = &q0, };
static logChannel_t s1 = { .readyQueue = &q1, };
static logChannel_t s2 = { .readyQueue = &q2, };
static logChannel_t s3 = { .logBuffer = ((void *)0x0), };
static logChannel_t s4 = { .logBuffer = ((void *)0x0), };
static logChannel_t s5 = { .logBuffer = ((void *)0x0), };
static logChannel_t s6 = { .logBuffer = ((void *)0x0), };
static logChannel_t s7 = { .logBuffer = ((void *)0x0), };
static logChannel_t s8 = { .logBuffer = ((void *)0x0), };
static logChannel_t s9 = { .logBuffer = ((void *)0x0), };
Assembly
.data .align 2 .elfsym ||q0||,SYM_SIZE(4) ||q0||: .bits 0,32 ; q0.next @ 0 .bits 0,16 ; q0.id @ 32 .bits 0,16 ; q0.size @ 48 .bits 0,16 ; q0[0] @ 64 .bits 0,16 ; q0[1] @ 80 .bits 0,16 ; q0[2] @ 96 .bits 0,16 ; q0[3] @ 112 .bits 0,16 ; q0[4] @ 128 .bits 0,16 ; q0[5] @ 144 .bits 0,16 ; q0[6] @ 160 etc same for q1, q2 as above NOTE: each of above is actually 11 words though 12 words with alignment so above should consume 36 words of the data page .data .align 2 .elfsym ||s0||,SYM_SIZE(8) ||s0||: .bits 0,16 ; s0.destination @ 0 .space 16 .bits 0,32 ; s0.logBuffer @ 32 .bits ||q0||,32 ; s0.readyQueue @ 64 .space 32 etc same for s1, s2 as above NOTE: using correct size of 12 words for each q0,1,2 causes below to start at word 60, and halfway through below is word 64 which is start of next data page .data .align 2 .elfsym ||s3||,SYM_SIZE(8) ||s3||: .bits 0,16 ; s3.destination @ 0 .space 16 .bits 0,32 ; s3.logBuffer @ 32 .space 64
And with incorrect size 4 set for q0,1,2 the
code generator incorrectly determines data page
boundary to be within s7 such that accessing 2nd
member of s7 requires new DP to be loaded.
original description:
The attached C file has these lines ...
static logChannel_t s3 = { .logBuffer = ((void *)0x0), };
static logChannel_t s4 = { .logBuffer = ((void *)0x0), };
/* next 2 lines are inside a function */
s3.logBuffer = localLogBuffer;
s4.logBuffer = localLogBuffer;
Build it ...
% cl2000 -@options.txt file.c
A page boundary at offset 0x40 passes through the middle of s3, The field logBuffer is before the page boundary. This can be seen with these snippets of the assembly listing file ...
191 0000003c ||s3||:
208 00000044 ||s4||:
The assembly code issued for these statements is ...
MOVL @||s3||,ACC ; [CPU_ALU] |1479|
MOVL @||s4||,ACC ; [CPU_ALU] |1480|
Because of the page boundary, the DP register should be updated between these two MOVL instructions, but it isn't.