C compiler error or program error?

I use the IAR C compiler to create an application for embedded micro (in particular, Renesas uPD78F0537). In this application, I use two nested loops to initialize some data, as shown below: MCVE :

#include <stdio.h> #define NUM_OF_OBJS 254 #define MAX_OBJ_SIZE 4 unsigned char objs[NUM_OF_OBJS][MAX_OBJ_SIZE]; unsigned char srcData[NUM_OF_OBJS][MAX_OBJ_SIZE]; void main(void) { srcData[161][2] = 10; int x, y; for (x = 0; x < NUM_OF_OBJS; x++) { for (y = 0; y < MAX_OBJ_SIZE; y++) { objs[x][y] = srcData[x][y]; } } printf("%d\n", (int) objs[161][2]); } 

The output value is 0, not 10.

The compiler generates the following code for the for loop:

  13 int x, y; 14 for (x = 0; x < NUM_OF_OBJS; x++) \ 0006 14.... MOVW DE,#objs \ 0009 16.... MOVW HL,#srcData 15 { 16 for (y = 0; y < MAX_OBJ_SIZE; y++) \ 000C A0F8 MOV X,#248 17 { 18 objs[x][y] = srcData[x][y]; \ ??main_0: \ 000E 87 MOV A,[HL] \ 000F 95 MOV [DE],A 19 } \ 0010 86 INCW HL \ 0011 84 INCW DE \ 0012 50 DEC X \ 0013 BDF9 BNZ ??main_0 20 } 

The above doesn't work: the compiler seems to pre-compute NUM_OF_OBJS x MAX_OBJ_SIZE = 1016 (0x3f8). This value is used as a counter, but it is truncated to 8 bits (0xf8 == 248) and stored in the 8-bit register "X". As a result, only the first 248 bytes of data are initialized, not the full 1016 bytes.

I can get around this, however my question is: is this a compiler error? Or am I not noticing something?


Update

  • This microcontroller has 7 Kbytes of RAM, and sizeof (int) == 2
  • Copying data using pointers (for example, something along the while (len-- > 0) *dst++ = *src++; lines while (len-- > 0) *dst++ = *src++; ) works fine.
+7
c embedded iar
source share
3 answers

I am pretty much convinced that this is a compiler error based on the following:

  • Copying data using pointers (for example, something along the while (len-- > 0) *dst++ = *src++; lines while (len-- > 0) *dst++ = *src++; ) works fine. So this is not like RAM size, pointer size, etc.

  • Perhaps more relevant: if I just replace one of the two constants ( NUM_OF_OBJS or MAX_OBJ_SIZE ) with a static variable (thereby preventing a preliminary calculation of the total number of compilers), it works fine.

Unfortunately, I contacted the IAR (providing a link to this SO question) and this is their answer:

Sorry that you do not have a license / support agreement (SUA). An exam, such as necessary for this occasion, can take time, and we (after-sales support) give priority to the time and efforts of users with a valid SUA.

Along with some general comments that are not particularly useful.

So, I assume that I just assume that this is a mistake and get around it in my code (there are many possible workarounds, including those described above).

+1
source share

Given that this is complete code, the compiler is not required to do anything, because the code is nonsense. The compiler is free to optimize the entire cycle because it does nothing.

A fully standard compatible compiler must initialize both objs and srcData for all zeros, since they have a static storage duration.

Therefore, a nested loop does nothing but skew zeros from one array to another. If the compiler notices that this loop is pointless, it can completely remove the loop.

Of course, it makes no sense to reduce the number of iterations in the loop as a way of optimization, so you may wonder what strange decisions the optimizer made in order to come up with this machine code. Odd and dumb, as it may seem, it is fully consistent with the standard.

You can declare cycle iterators as volatile to force side effects. In this case, the loop should be executed even if it is pointless, since reading / writing to the volatile variable is a side effect that the compiler cannot optimize.

Please keep in mind that embedded system compilers often have a non-standard “minimum run” option when they skip initializing static storage duration variables to speed up system loading. If such a non-standard option is enabled, the variables will contain garbage values ​​instead of zeros.

0
source share

Although it is technically possible to assume that these arrays are in .bss and are nullified, compilers now issue warnings when you really make this assumption and read something from bss before writing it. Being a global interrupt, etc., These arrays can appear and change, so this is a really safe assumption (by the compiler) that they are zeros. Gcc does not make this assumption that it copies the entire array. Clang / llvm also copies the entire array, does not accept the shortcut. A label would be like writing a single value to both arrays and printing that value instead of copying the entire array.

Interestingly, even if arrays were declared static or made local, gcc cannot determine a shortcut that is strange for gcc, which is no better, but usually calculates much more complex dead code outlines.

What is the int size defined for this purpose by the compiler, perhaps int has a size of 8 bits, and the compiler performed the action you specified. If not, maybe yes, this is a compiler error. Try making 254 a bit smaller, whether it will change 0xF8 by a proportional amount, whether it always looks like it is cutting out the lower 8 bits or is it some kind of magic number that has 0xF8 with 1016 or 254 or 161, etc.

0
source share

All Articles