Bug 36340 - avr-gcc misoptimalizes loops
Summary: avr-gcc misoptimalizes loops
Status: RESOLVED DUPLICATE of bug 21920
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.2.4
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2008-05-27 09:45 UTC by Daniel Rozsnyo
Modified: 2008-05-27 10:27 UTC (History)
25 users (show)

See Also:
Target: avr
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Rozsnyo 2008-05-27 09:45:06 UTC
  I'm working on an UDP layer and I discovered a bug when the optimalization level is set to -O2 or -Os. The only working option is -O1 (except the -O0 which shows a warning that it is not good to use it with avr).

The bit of code is here:

uint16_t ip_udp_cksum(ip_packet_t *ip) {
    udp_checksum_t ph;
    uint32_t       sum = 0;
    uint8_t        i = sizeof(ph) / 2; // 12/2=6
    // A
    ph.src     = ip->header->src;
    // B
    ph.dst     = ip->header->dst;
    // C
    ph.zeros   = 0x00;
    ph.proto   = IPPROTO_UDP;
    ph.udpsz   = ((udp_header_t*)ip->data)->len;
    // sum the pseudo header
    while(i--) {
        sum += ntohs(((uint16_t*)&ph)[i]);
    // do the rest
    return in_cksum(ip->data,ip->size,sum);

Problem is with the sum value, which is wrong when the stronger optimalisation is on. I tried to call a function to write out the summarized components, but in that case the sum was OK even with -O2 or -Os.

So I suspect some misoptimalization in conjunction with unwinding of loops maybe? The same applies if I change the code to for-loop with i=0..5.

With -O1 the above code works correctly.

The same applies for GCC version 4.2.3 and 4.2.4.
Comment 1 Andrew Pinski 2008-05-27 09:57:51 UTC

You are violating C/C++ aliasing rules as you are accessing ph (a udp_checksum_t) as an unit16_t.

*** This bug has been marked as a duplicate of 21920 ***
Comment 2 Daniel Rozsnyo 2008-05-27 10:27:29 UTC
Thank you. Problem solved with:

    // type conversion
    typedef union {
        udp_checksum_t udp;
        uint16_t       raw[sizeof(udp_checksum_t)/2];
    } udp_checksum_u;

filling out ph.udp and summarizing values from ph.raw