gcc -Wmaybe-uninitialized warning and optimization problem

37 views Asked by At

I have written a bitHelper function with three tests. This bitHelper function is accutually a memcpy but at bit level, it copies width bits from inWords array to outWords array, with bits offset specified by inLsb, outLsb.

#include <bitset>
#include <iostream>
#include <memory>

template <typename OutWordT, typename InWordT>
void bitHelper22(OutWordT *outWords, uint32_t outLsb, const InWordT *inWords,
                 uint32_t inLsb, uint32_t width) {
    if (width == 0)
        return;
    uint32_t outSizeb = sizeof(OutWordT) * 8;
    uint32_t outIndexOff = outLsb / outSizeb;
    uint32_t outBitOff = outLsb % outSizeb;

    uint32_t inSizeb = sizeof(InWordT) * 8;
    uint32_t inIndexOff = inLsb / inSizeb;
    uint32_t inbitOff = inLsb % inSizeb;

    uint32_t validBits = 0;
    uint32_t needBits = outSizeb - outBitOff;

    InWordT inword = 0;
    OutWordT outword = 0;
    while (width > 0) {
        uint32_t readBits = outSizeb - needBits - outBitOff;
        if (validBits >= needBits || validBits + readBits >= width) {
            OutWordT widthMask = outBitOff + width >= outSizeb
                                     ? ~(OutWordT)0
                                     : (((OutWordT)1 << width) - 1);
            widthMask <<= outBitOff;

            outword |= (OutWordT)inword << (outSizeb - needBits);
            outWords[outIndexOff] =
                (outWords[outIndexOff] & ~widthMask) | (outword & widthMask);
            if (width <= outSizeb - outBitOff)
                break;
            width -= outSizeb - outBitOff;

            if (needBits >= inSizeb)
                inword = 0;
            else
                inword >>= needBits;
            validBits -= needBits;
            needBits = outSizeb;

            outIndexOff++;
            outBitOff = 0;
            outword = 0;
        } else {
            outword |= (OutWordT)inword << (outSizeb - needBits);
            needBits -= validBits;

            inword = inWords[inIndexOff] >> inbitOff;
            validBits = inSizeb - inbitOff;
            inIndexOff++;
            inbitOff = 0;
        }
    }
    // std::cout << "inIdex: " << inIndexOff << std::endl;
    // std::cout << "outIndex: " << outIndexOff << std::endl;
}

int test4() {
    uint64_t inWord =
        0x5555555555555555; // 0b0101_0101_0101_0101_0101_0101_0101_0101
    uint64_t outWord = 0;
    // It's valid in little-endian machine to reinterpret as `uint16_t*`
    bitHelper22((uint16_t *)&outWord, 12, &inWord, 1, 44);
    std::bitset<64> in(inWord), out(outWord);
    std::cout << "[test4: 12,1,44] in: " << in << ", out: " << out << std::endl;
    return outWord != 0xaaaaaaaaaaa000;
}

int test5() {
    uint64_t inWord =
        0x5555555555555555; // 0b0101_0101_0101_0101_0101_0101_0101_0101
    uint64_t outWord = 0;
    // It's valid in little-endian machine to reinterpret as `uint16_t*`
    bitHelper22(&outWord, 4, (uint16_t *)&inWord, 7, 44);
    std::bitset<64> in(inWord), out(outWord);
    std::cout << "[test5: 4,7,44] in: " << in << ", out: " << out << std::endl;
    return outWord != 0xaaaaaaaaaaa0;
}

int test8() {
    uint64_t inWord =
        0x5555555555555555; // 0b0101_0101_0101_0101_0101_0101_0101_0101
    uint64_t inWords[2] = {inWord, inWord};
    uint64_t outWord = 0;
    // It's valid in little-endian machine to reinterpret as `uint16_t*`
    bitHelper22((uint16_t *)&outWord, 4, (uint32_t *)inWords, 40, 44);
    std::bitset<64> in(inWord), out(outWord);
    std::cout << "[test8: 4,40,44] in: " << in << ", out: " << out << std::endl;
    return outWord != 0x555555555550;
}

int main() {
    if (test4()) {
        std::cout << "TEST4 FAILED!" << std::endl;
    }
    if (test5()) {
        std::cout << "TEST5 FAILED!" << std::endl;
    }
    if (test8()) {
        std::cout << "TEST8 FAILED!" << std::endl;
    }
    return 0;
}

clang++ and g++ compiling this program show different results. Program compiled by clang++ (version 15.0.7) will pass three tests with -O3 optimization.

While using g++(version 8.3.0 and version 14.0.0), the compiled program will pass three tests with -O1 optimization, but failed at test4, test8 with -O2 or -O3 optimization.

If I add -Wall flags, g++(version 14.0.0) will warn

In function ‘void bitHelper22(OutWordT*, uint32_t, const InWordT*, uint32_t, uint32_t) [with OutWordT = long unsigned int; InWordT = short unsigned int]’,
    inlined from ‘int test5()’ at test2.cpp:78:16:
test2.cpp:52:29: warning: ‘inWord’ may be used uninitialized [-Wmaybe-uninitialized]
   52 |             inword = inWords[inIndexOff] >> inbitOff;
      |                      ~~~~~~~^
test2.cpp: In function ‘int test5()’:
test2.cpp:74:14: note: ‘inWord’ declared here
   74 |     uint64_t inWord =
      |              ^~~~~~
In function ‘void bitHelper22(OutWordT*, uint32_t, const InWordT*, uint32_t, uint32_t) [with OutWordT = short unsigned int; InWordT = unsigned int]’,
    inlined from ‘int test8()’ at test2.cpp:90:16:
test2.cpp:52:29: warning: ‘inWords’ may be used uninitialized [-Wmaybe-uninitialized]
   52 |             inword = inWords[inIndexOff] >> inbitOff;
      |                      ~~~~~~~^
test2.cpp: In function ‘int test8()’:
test2.cpp:87:14: note: ‘inWords’ declared here
   87 |     uint64_t inWords[2] = {inWord, inWord};
      |

I can't see why this warning is triggered....

I would very appriciate it if you can point out whether a UB exists in my program. Or, gcc has any option to dump each optimization pass to find which pass does some unexpected optimization? (I am familiar with llvm IR, but have no idea about IR used by gcc.)

0

There are 0 answers