g++ optimizations prevent my code to work - Stack Overflow

My code works in debug mode. In release mode, however, I have to disable all optimizations with the -O0

My code works in debug mode. In release mode, however, I have to disable all optimizations with the -O0 flag. I would like to understand what the problem is and how I could use some optimizations.

I am programming on Linux installed in a SoC FPGA (i.e. an FPGA with a hardware ARM core). To exchange data with the firmware (FPGA side), I map the FPGA memory to the Linux address space and use the following two macros to respectively read from and write to the firmware, on a 32-bit data bus:

#define IORD(base, index)                   (*(((uint32_t *)base)+index))
#define IOWR(base, index, data)             (*(((uint32_t *)base)+index) = data)

Memory mapping and offset calculation:

void *h2f_virtual_base;
uint32_t *ravioliDigProc_addr = NULL;

h2f_virtual_base = mmap(NULL, H2F_SPAN, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, H2F_BASE);
ravioliDigProc_addr = (uint32_t*) ((uint8_t*) h2f_virtual_base + (RAVIOLIDIGPROC_0_BASE & H2F_MASK));

The core of this test code consists in the while loop below. The normal behavior it to read the 2048 values in the firmware buffer and exit the loop.

When optimizations are enabled, no value is read and the loop exits at the 1st iteration. Interestingly, if I swap the test and the fprintf() call, it loops 40000 times and writes the same values 40000 times in the file.

        while( (test != 0) && (ne < 40000) ) {
            volatile uint32_t data1, data2;
            volatile uint32_t d1, d2, d3, d4;
            IOWR(ravioliDigProc_addr, 0x0003, 0x00000008);
            IOWR(ravioliDigProc_addr, 0x0003, 0x00000000);
            data1 = IORD(ravioliDigProc_addr, 0x0004);
            data2 = IORD(ravioliDigProc_addr, 0x0005);
            myData = IORD(ravioliDigProc_addr, 0x0003);
            d1 = data1 & 0xFFFF;
            d2 = (data1 & 0xFFFF0000)>>16;
            d3 = data2 & 0xFFFF;
            d4 = (data2 & 0xFFFF0000)>>16;
            test = myData & 0x00010000;
            if(!test) {
                printf("test == 0: ne = %d\n", ne);
                break;
            }
            fprintf(pFile, "%d,%d,%d,%d\n", d1, d2, d3, d4);
            ne++;
        }
        printf("%d values saved\n", ne);
        printf("After while:\t0x%02x: 0x%08x\n", 0x0003, myData);

If disabling all optimization is the only option, is it possible to do so only on some parts of the code or on some files?

My code works in debug mode. In release mode, however, I have to disable all optimizations with the -O0 flag. I would like to understand what the problem is and how I could use some optimizations.

I am programming on Linux installed in a SoC FPGA (i.e. an FPGA with a hardware ARM core). To exchange data with the firmware (FPGA side), I map the FPGA memory to the Linux address space and use the following two macros to respectively read from and write to the firmware, on a 32-bit data bus:

#define IORD(base, index)                   (*(((uint32_t *)base)+index))
#define IOWR(base, index, data)             (*(((uint32_t *)base)+index) = data)

Memory mapping and offset calculation:

void *h2f_virtual_base;
uint32_t *ravioliDigProc_addr = NULL;

h2f_virtual_base = mmap(NULL, H2F_SPAN, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, H2F_BASE);
ravioliDigProc_addr = (uint32_t*) ((uint8_t*) h2f_virtual_base + (RAVIOLIDIGPROC_0_BASE & H2F_MASK));

The core of this test code consists in the while loop below. The normal behavior it to read the 2048 values in the firmware buffer and exit the loop.

When optimizations are enabled, no value is read and the loop exits at the 1st iteration. Interestingly, if I swap the test and the fprintf() call, it loops 40000 times and writes the same values 40000 times in the file.

        while( (test != 0) && (ne < 40000) ) {
            volatile uint32_t data1, data2;
            volatile uint32_t d1, d2, d3, d4;
            IOWR(ravioliDigProc_addr, 0x0003, 0x00000008);
            IOWR(ravioliDigProc_addr, 0x0003, 0x00000000);
            data1 = IORD(ravioliDigProc_addr, 0x0004);
            data2 = IORD(ravioliDigProc_addr, 0x0005);
            myData = IORD(ravioliDigProc_addr, 0x0003);
            d1 = data1 & 0xFFFF;
            d2 = (data1 & 0xFFFF0000)>>16;
            d3 = data2 & 0xFFFF;
            d4 = (data2 & 0xFFFF0000)>>16;
            test = myData & 0x00010000;
            if(!test) {
                printf("test == 0: ne = %d\n", ne);
                break;
            }
            fprintf(pFile, "%d,%d,%d,%d\n", d1, d2, d3, d4);
            ne++;
        }
        printf("%d values saved\n", ne);
        printf("After while:\t0x%02x: 0x%08x\n", 0x0003, myData);

If disabling all optimization is the only option, is it possible to do so only on some parts of the code or on some files?

Share Improve this question asked Mar 21 at 9:27 dpengdpeng 4872 gold badges7 silver badges17 bronze badges 4
  • 1 ravioliDigProc_addr should probably be a pointer to volatile. volatile on local variables doesn't make much sense. – Mat Commented Mar 21 at 9:32
  • Note the macro must also be modified to use pointer on volatile values in order to avoid an undefined behaviour: (volatile uint32_t *). Btw, I think it is fine to use the base[index] syntax here (easier to read). – Jérôme Richard Commented Mar 21 at 12:59
  • Technically, to be safer and be sure to avoid any UB due to aliasing rules, you shoule avoid things like (uint32_t*) ((uint8_t*) .... uintptr_t should be used for arithmetic instead. std::bit_cast should also be fine here. Note the offset must be aligned to sizeof(uint32_t) or this is UB otherwise. – Jérôme Richard Commented Mar 21 at 13:02
  • Regarding performance, I think it is better to shift+cast, rather than mask+shift, especially on FPGA where I guess casting of smaller integer types is a no-op. GCC might detect this pattern though. – Jérôme Richard Commented Mar 21 at 13:06
Add a comment  | 

1 Answer 1

Reset to default 0

In release mode, however, I have to disable all optimizations with the -O0 flag.

There are only two reasons for this behavior:

  1. There is a bug in your program -- it exercises some kind of undefined behavior, and compiler optimization takes advantage of that (e.g. by removing all code which would lead to actual execution of UB).
  2. There is a compiler bug.

In 99.99% of the cases where optimization leads to wrong result, the programmer is at fault.

In the other 0.01% of the cases, there is a compiler bug.

I would like to understand what the problem is and how I could use some optimizations.

Without an MCVE, nobody can really help you (although some comments have already pointed out problematic code).

Your best bet is to make unit tests which can run on your development machine and exercise most of your code, and then run these unit tests with AddressSanitizer, UndefinedBehaviorSanitizer, etc. etc.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744363602a4570590.html

相关推荐

  • g++ optimizations prevent my code to work - Stack Overflow

    My code works in debug mode. In release mode, however, I have to disable all optimizations with the -O0

    7天前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信