https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126509

            Bug ID: 126509
           Summary: Wrong code with bitint bitfields
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ktkachov at gcc dot gnu.org
                CC: jakub at gcc dot gnu.org
  Target Milestone: ---

#define NOIPA __attribute__((noipa))

#define TEST(P, L, K)                                                   \
  typedef unsigned _BitInt(P) U##P##_##K;                               \
  struct S##P##_##K { unsigned long long lead : L;                      \
                      unsigned _BitInt(P) f : K; };                     \
  NOIPA static void st##P##_##K (struct S##P##_##K *p, U##P##_##K v)    \
  { p->f = v; }                                                         \
  NOIPA static U##P##_##K ld##P##_##K (struct S##P##_##K *p)            \
  { return p->f; }                                                      \
  NOIPA static U##P##_##K add##P##_##K (struct S##P##_##K *p, U##P##_##K v) \
  { return (U##P##_##K) (p->f + v); }                                   \
  NOIPA static U##P##_##K xor##P##_##K (struct S##P##_##K *p, U##P##_##K v) \
  { return (U##P##_##K) (p->f ^ v); }                                   \
  NOIPA static U##P##_##K not##P##_##K (struct S##P##_##K *p)           \
  { return (U##P##_##K) ~p->f; }                                        \
  NOIPA static U##P##_##K id##P##_##K (U##P##_##K v)                    \
  { volatile U##P##_##K t = v; return t; }                              \
  NOIPA static U##P##_##K ref##P##_##K (U##P##_##K v)                   \
  {                                                                     \
    volatile U##P##_##K t = (U##P##_##K) (v << ((P) - (K)));            \
    volatile U##P##_##K u = (U##P##_##K) (t >> ((P) - (K)));            \
    return u;                                                           \
  }                                                                     \
  static void chk##P##_##K (void)                                       \
  {                                                                     \
    static struct S##P##_##K b;                                         \
    U##P##_##K v[4];                                                    \
    v[0] = (U##P##_##K) 1 << ((K) - 1);                                 \
    v[1] = (U##P##_##K) ~(U##P##_##K) 0;                                \
    v[2] = (U##P##_##K) 1 << (((K) / 64) * 64);                         \
    v[3] = (U##P##_##K) 0x0123456789abcdefULL;                          \
    for (int i = 0; i < 4; i++)                                         \
      {                                                                 \
        U##P##_##K w = v[i];                                            \
        st##P##_##K (&b, w);                                            \
        U##P##_##K f = ld##P##_##K (&b);                                \
        if (f != ref##P##_##K (w))                                      \
          __builtin_abort ();                                           \
        if (add##P##_##K (&b, id##P##_##K (w))                          \
            != (U##P##_##K) (ref##P##_##K (w) + id##P##_##K (w)))       \
          __builtin_abort ();                                           \
        if (xor##P##_##K (&b, id##P##_##K (w))                          \
            != (U##P##_##K) (ref##P##_##K (w) ^ id##P##_##K (w)))       \
          __builtin_abort ();                                           \
        if (not##P##_##K (&b) != (U##P##_##K) ~ref##P##_##K (w))        \
          __builtin_abort ();                                           \
      }                                                                 \
  }

TEST (256, 1, 193)
TEST (320, 1, 193)
TEST (385, 3, 321)
TEST (512, 1, 449)
TEST (575, 1, 511)

/* The same defect with a SIGNED bit-field.  The arithmetic is still done in
   the unsigned type so that no signed overflow can occur.  */

typedef _BitInt(256) S256;
typedef unsigned _BitInt(256) U256;

struct SB { unsigned long long lead : 1; S256 f : 193; };

NOIPA static S256 mk (U256 v) { volatile S256 t = (S256) v; return t; }
NOIPA static void sst (struct SB *p, S256 v) { p->f = v; }
NOIPA static U256 sld (struct SB *p) { return (U256) p->f; }
NOIPA static U256 sadd (struct SB *p, U256 v) { return (U256) ((U256) p->f +
v); }
NOIPA static U256 sxor (struct SB *p, U256 v) { return (U256) ((U256) p->f ^
v); }
NOIPA static U256 sid (U256 v) { volatile U256 t = v; return t; }

static struct SB sb;
static void
chk_signed (void)
{
  U256 v[3];
  v[0] = (U256) 1 << 192;
  v[1] = (U256) ~(U256) 0;
  v[2] = (U256) 1 << 191;
  for (int i = 0; i < 3; i++)
    {
      sst (&sb, mk (v[i]));
      U256 f = sld (&sb);
      if (sadd (&sb, sid (v[i])) != (U256) (f + sid (v[i])))
        __builtin_abort ();
      if (sxor (&sb, sid (v[i])) != (U256) (f ^ sid (v[i])))
        __builtin_abort ();
    }
}

int
main (void)
{
  chk256_193 ();
  chk320_193 ();
  chk385_321 ();
  chk512_449 ();
  chk575_511 ();
  chk_signed ();
  return 0;
}

Aborts on aarch64 at -O2 and doesn't at -O0

Reply via email to