Word arounds for incorrect result with uint128_t on PPC64?

Jeffrey Walton noloader@gmail.com
Sat May 13 04:34:00 GMT 2017


We have some self tests failing on GCC compile farm host gcc110. Its a
POWER7 machine running Fedora 20.

When I run the program below with the default compiler, GCC 4.8, I
arrive at the wrong result. The program rounds the first number up to
the second number. The result below should be the pair (1,8), not
(1,7):

gcc1-power7]$ ./test.exe
00000000000000000000000000000001
00000000000000000000000000000007

Using GCC 7.1 in /opt on gcc110 produces the expected result. Running
on other machines, like x86_64 produces the expected result. Changing
optimization levels does not help the problem under GCC 4.8.

The GCC bugzilla is timing out, so I'm having trouble searching it.

Does anyone know what the issue is, and is there a way to work around it?

==========

Command line:

    g++ -g2 -O5 -Wall -Wextra test.cxx -o test.exe

Test program:

$ cat test.cxx
#include <iostream>
#include <iomanip>
#include <limits>
#include <stdexcept>
#include <stdint.h>
#include <assert.h>
using namespace std;

#if (__SIZEOF_INT128__ >= 16)
# define INT128_AVAILABLE 1
typedef __uint128_t word128;
#endif

template<class T>
T NumericLimitsMax()
{
  assert(std::numeric_limits<T>::is_specialized);
  return (std::numeric_limits<T>::max)();
};

template <class T>
inline bool IsPowerOf2(const T &value)
{
  return value > 0 && (value & (value-1)) == 0;
}

template <class T1, class T2>
inline T2 ModPowerOf2(const T1 &a, const T2 &b)
{
  return T2(a) & (b-1);
}

template <class T1, class T2>
inline T1 RoundDownToMultipleOf(const T1 &n, const T2 &m)
{
  assert(!std::numeric_limits<T1>::is_signed || n > 0);
  assert(!std::numeric_limits<T2>::is_signed || m > 0);

  if (IsPowerOf2(m))
    return n - ModPowerOf2(n, m);
  else
    return n - n%m;
}

template <class T1, class T2>
inline T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
{
  // Overflow detection omitted
  return RoundDownToMultipleOf(T1(n+m-1), m);
}

inline ostream& operator<<(ostream& stm, const word128& val)
{
  uint64_t h = (uint64_t)(val >> 64U);
  uint64_t l = (uint64_t)val;
  stm << hex << setfill('0') << setw(16) << h;
  stm << hex << setfill('0') << setw(16) << l;
  return stm;
}

int main(int argc, char* argv[])
{
  word128 x = 1, b = 8;
  cout << hex << x << endl;
  cout << RoundUpToMultipleOf(x, b) << endl;
  return 0;
}



More information about the Gcc-help mailing list