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

            Bug ID: 85446
           Summary: [7/8 Regression] wrong-code on riscv64
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakub at gcc dot gnu.org
  Target Milestone: ---

Starting with r238754 we can miscompile narrowing conversion of pointer to
integer compared against constant (unfortunately the only testcase for this I
have is for riscv64 (due to different IVOPTS decisions) which has been
introduced in r245224, so technically this is just latent bug).

Testcase for -O2 -fwrapv -fno-strict-aliasing -mabi=lp64 -march=rv64g
typedef struct
{
  void *cdr;
  void *car;
} cons_;
typedef cons_ *Cons;
typedef struct
{
  union
  {
    void *_GCself;
    unsigned char flags[sizeof (void *) / sizeof (unsigned char)];
  } header;
  void *symvalue;
  void *symfunction;
  void *hashcode;
  void *proplist;
  void *pname;
  void *homepackage;
} symbol_;
typedef symbol_ *Symbol;
typedef struct
{
  union
  {
    void *_GCself;
    unsigned char flags[sizeof (void *) / sizeof (unsigned char)];
  } header;
  signed char rectype;
  unsigned char recflags;
  unsigned char reclength;
  unsigned char recxlength;
  void *ht_maxcount;
  void *ht_kvtable;
  void *ht_lookupfn;
  void *ht_hashcodefn;
  void *ht_testfn;
  void *ht_gcinvariantfn;
  void *ht_rehash_size;
  void *ht_mincount_threshold;
  void *ht_mincount;
  void *ht_test;
  void *ht_hash;
  unsigned int ht_size;
} *Hashtable;
typedef struct
{
  union
  {
    void *_GCself;
    unsigned char flags[sizeof (void *) / sizeof (unsigned char)];
  } header;
  unsigned int length;
  void *hal_filler;
  void *hal_itable;
  void *hal_count;
  void *hal_freelist;
  void *hal_data[0];
} *HashedAlist;
extern void **STACK;
extern struct symbol_tab_
{
  symbol_ S_nil;
  symbol_ S_t;
} symbol_tab_data;
extern unsigned int mv_count;
extern void *mv_space[127];
void
C_hash_table_iterate (void)
{
  void *state = (STACK -= 1, STACK[0]);
  if (((unsigned long) state) & (1UL << 62))
    {
      void *table = ((Cons) ((void *) ((unsigned long) state & ((1UL << 56) -
1))))->car;
      while (1)
        {
          unsigned int index = (unsigned long) ((unsigned long) ((((Cons)
((void *) ((unsigned long) state & ((1UL << 56) - 1))))->cdr)) & ((2UL << 55) -
1));
          if (index == 0)
            break;
          ((Cons) ((void *) ((unsigned long) state & ((1UL << 56) - 1))))->cdr
= ((void *) ((unsigned char *) ((((Cons) ((void *) ((unsigned long) state &
((1UL << 56) - 1))))->cdr)) + (long) (-1)));
          {
            void **KVptr = &((HashedAlist) ((void *) ((unsigned long) table &
((1UL << 56) - 1))))->hal_data[3 * index - 3];
            if (!(KVptr[0] == (void *) 0x380000000FFFFFFUL))
              {
                mv_space[0] = (void *) ((unsigned char *)
(&symbol_tab_data.S_t) + (1UL << 58));
                mv_space[1] = KVptr[0];
                mv_space[2] = KVptr[1];
                mv_count = 3;
                return;
              }
          }
        }
    }
  mv_space[0] = (void *) ((unsigned char *) (&symbol_tab_data.S_nil) + (1UL <<
58));
  mv_count = 1;
}

The difference between cddce3 and forwprop4 shows the bug:
   unsigned int index;
...
   void * prephitmp_40;
...
   <bb 4> [local count: 1073741825]:
   # prephitmp_40 = PHI <pretmp_35(3), _11(5)>
   # ivtmp.14_36 = PHI <ivtmp.14_42(3), ivtmp.14_9(5)>
   index_46 = (unsigned int) prephitmp_40;
-  if (index_46 == 0)
+  if (prephitmp_40 == 0B)
     goto <bb 7>; [5.50%]
   else
     goto <bb 5>; [94.50%]

The original was comparing only the low 32-bits of the pointer against 0, the
modified code compares the whole pointer against NULL.

Reply via email to