Equality wrong on Power

[ The forum don’t like angle brackets in the include statements. Thus they were removed. ]

Hi,

I’m using PGI 19.4 on Power and it behaves weird when it comes to comparing signed integer constants:

#ifdef GOOD
#  include stdint.h
#endif
#include stdlib.h
#ifndef GOOD
#  include stdint.h
#endif
#include assert.h

int
main(int ac, char *av[])
{
    assert(-128 == (int8_t)-128);
    return 0;
}

Compiling this triggers the assert:

$ pgcc -V
pgcc 19.4-0 linuxpower target on Linuxpower 
PGI Compilers and Tools
Copyright (c) 2019, NVIDIA CORPORATION.  All rights reserved.
$ pgcc -o test-undefined.pgi test-undefined.c
$ ./test-undefined.pgi
test-undefined.pgi: test-undefined.c:13: main: Assertion `-128 == (int8_t)-128' failed.
Aborted

Changing the include order to stdint.h and stdlib.h works:

$ pgcc -DGOOD -o test-undefined.pgi test-undefined.c
$ ./test-undefined.pgi

The preprocessed sources do not look that different. I can provide these, if requested.

I don’t see this behavior on Linux x86-64.

Thanks for looking into this.

Hi Bert,

Thanks. I was able to replicate the problem on power, I’ve assigned the problem TPR #27623.

Hi Bert,

While I’ll ask Alex to keep TPR#27263 open in case we can find a work around, this is not a PGI issue but rather an issue with the system header files.

Short answer: Add “-Mschar” to the compile.

% pgcc test-undefined.c -Mschar
% a.out
%

Long answer:

When “stdlib.h” is included before “stdint.h”, the “sys/types.h” header file (included in stdlib.h) defines “int8_t” as a “char” when not using GNUC 2.7 or newer:

#if !__GNUC_PREREQ (2, 7)

/* These types are defined by the ISO C99 header <inttypes.h>. */
# ifndef __int8_t_defined
#  define __int8_t_defined
typedef char int8_t;
typedef short int int16_t;
typedef int int32_t;
#  if __WORDSIZE == 64
typedef long int int64_t;
#  elif __GLIBC_HAVE_LONG_LONG
__extension__ typedef long long int int64_t;
#  endif
# endif

Switching the order of the include files, “int8_t” is typedef’d to “signed char” in “stdint.h”. Given “char” is unsigned by default on Power (it’s signed on x86), the assert fails since you’re casting “-128” to an unsigned value. The solution is to add “-Mschar” to the compilation to change the default of char from unsigned to signed.

In order to work around the issue, we’d need to ship our own “sys/types.h” file, which I’m hesitant to do, but I’ll let our engineers decide if that’s the best route to go.

Hope this helps,
Mat

Thanks Mat for the investigation, much appreciated.

It looks like, that with GLIBC 2.26 (released 2017-08-02) the problem disappear, as this removes this ‘__GNUC_PREREQ (2, 7)’.

But the whole situation is rather unlucky for an library provider which uses int8_t in its API. Forcing the library user to add -Mschar does not seem to be a good option, and also ensuring that the library user has the correct include order too.

Best.
Bert

But the whole situation is rather unlucky for an library provider which uses int8_t in its API. Forcing the library user to add -Mschar does not seem to be a good option, and also ensuring that the library user has the correct include order too.

Understood, unfortunately there’s nothing we can do about the difference in the default signed vs unsigned char on Power vs x86.

For the system header, we would need to provide our own version of the file with the GNUisms worked around. We have several cases where we have to do this on x86 but it looks like we may need to do this on Power as well.

-Mat

Hi Bert,

FYI, since TPR#27623 only occurred with our older pgcc11 compiler which is now deprecated in 20.1, and works with our new pgcc18 compiler (which is the default pgcc in 20.1) we’ve decided close this issue.

-Mat