llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
26.96k stars 11.04k forks source link

Optimizer for __builtin_bswap32 fails #43455

Open llvmbot opened 4 years ago

llvmbot commented 4 years ago
Bugzilla Link 44110
Version 8.0
OS Linux
Reporter LLVM Bugzilla Contributor
CC @topperc,@DougGregor,@zygoloid

Extended Description

The following code runs OK in Compiler Explorer with opts: -std=c++11 -O1 Fails running: -std=c++11 -O3 Byte swapping is omitted.

#include <cstdint>
#include <cstdlib>
#include <iostream>

inline
static void swap(uint32_t & value)
{
    value = __builtin_bswap32(value);
}

inline
void swap(float & value)
{
    swap(*(reinterpret_cast<uint32_t*>(&value)));
}

// Swap an array of values
template<typename PtrType>
inline void swap(PtrType * data, size_t length)
{
    for (size_t i = 0; i < length; ++i)
        swap(data[i]);
}

template<typename T>
void output(const char * s, T v) // __attribute__((noinline))
{
  std::cout << s << ": " << v << std::endl;
}

int main()
{
    float vec1[2];
    vec1[0] = rand(); vec1[1] = rand();
    const float vec1Orig = vec1[0];
    output("vec1[0] value before swap", vec1[0]);
    swap(vec1, 2);
    if (vec1[0] == vec1Orig)
        output("Failed: vec1[0] value after swap", vec1[0]);
    else
        output("OK: vec1[0] value after swap", vec1[0]);
}
topperc commented 4 years ago

This code also fails with gcc compiled with -O3. It passes on both clang and gcc if you add -fno-strict-aliasing to the command line. I believe the problem lies in the reinterpret cast used to turn the float into a uint32_t.

This is a way to turn the float into a uint32_t and back that avoids the issue

inline
void swap(float & value)
{
    uint32_t tmp;
    memcpy(&tmp, &value, sizeof(float));
    swap(tmp);
    memcpy(&value, &tmp, sizeof(float));
}