With a 4.8-based compiler for ARM, I've observed an ICE in the
var-tracking.c:add_stores handling of COND_EXEC.  A large testcase
from building Qt can be found at
<https://bugs.launchpad.net/gcc-linaro/+bug/1312931>; a somewhat
reduced version (for the compiler with which I observed the problem)
is attached (to be built with -march=armv7-a -S -g -O2 -std=c++0x
-fno-exceptions -fPIE), but the issue seems very sensitive to details
of optimization and the test not really suitable for the testsuite.

The assertion

      gcc_assert (oval != v);

fails.  As I understand it, this is asserting that the conditional
store is not storing a value already present in the location in
question.  Now, it's not clear to me this should be relying on
optimizations like that.  In this case, the key peculiarity of the
code that may have caused the lack of optimization involves the
shared_null static const data member.  The destination of the problem
conditional store holds a value loaded from that member at some
point.  The source of that store was previously (conditionally, on the
same condition) stored into that constant location.  (Maybe in the
original code this store into a const location can't actually occur,
but that's the code being processed after inlining.)  So if you treat
that location as constant it follows that the two values are the same
(and that we have undefined behavior at runtime), while if you don't
then the values are clearly different (the store ends up being a
conditional increment).

This patch simply makes add_stores do nothing in this case of a
conditional store that does nothing.

Tested with no regressions for cross to arm-none-linux-gnueabi.  OK to
commit?

2014-06-27  Joseph Myers  <jos...@codesourcery.com>

        * var-tracking.c (add_stores): Return instead of asserting if old
        and new values for conditional store are the same.

Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c  (revision 211889)
+++ gcc/var-tracking.c  (working copy)
@@ -6014,7 +6014,8 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
     {
       cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
 
-      gcc_assert (oval != v);
+      if (oval == v)
+       return;
       gcc_assert (REG_P (oloc) || MEM_P (oloc));
 
       if (oval && !cselib_preserved_value_p (oval))

-- 
Joseph S. Myers
jos...@codesourcery.com
typedef unsigned int size_t;
namespace std
{
  typedef unsigned int size_t;
  template<typename _Tp> struct remove_reference
  {
    typedef _Tp type;
  };
  template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& 
move(_Tp&& __t) noexcept
  {
    return static_cast<typename std::remove_reference<_Tp>::type&&>(__t);
  }
  template<typename _Tp> inline void swap(_Tp& __a, _Tp& __b)
  {
    _Tp __tmp = std::move(__a);
    __a = std::move(__b);
    __b = std::move(__tmp);
  }
}
extern "C"
{
  inline void* operator new(std::size_t, void* __p) noexcept
  {
    return __p;
  }
}
struct QA1
{
  static inline int load(const int &_q_value) noexcept
  {
    return _q_value;
  }
  static bool aref(int &_q_value) noexcept
  {
    return ++_q_value != 0;
  }
  static bool aderef(int &_q_value) noexcept
  {
    return --_q_value != 0;
  }
};
class QB1
{
public:
  int _q_value;
  int baload() const noexcept
  {
    return QA1::load(_q_value);
  }
  bool baref() noexcept
  {
    return QA1::aref(_q_value);
  }
  bool baderef() noexcept
  {
    return QA1::aderef(_q_value);
  }
};
class QR
{
public:
  inline bool ref() noexcept
  {
    int count = qb.baload();
    if (count == 0) return false;
    if (count != -1) qb.baref();
    return true;
  }
  inline bool deref() noexcept
  {
    int count = qb.baload();
    if (count == 0) return false;
    if (count == -1) return true;
    return qb.baderef();
  }
  bool isShared() const noexcept
  {
    int count = qb.baload();
    return (count != 1) && (count != 0);
  }
  QB1 qb;
};
extern "C"
{
  extern size_t strlen (const char *__s) throw ();
}
struct QArrayData
{
  QR ref;
  static void deallocate(QArrayData *data, size_t objectSize, size_t alignment);
  static const QArrayData shared_null[2];
  static QArrayData *sharedNull()
  {
    return const_cast<QArrayData*>(shared_null);
  }
};
struct QTypedArrayData : QArrayData
{
  QArrayData header;
  static void deallocate(QArrayData *data)
  {
    QArrayData::deallocate(data, sizeof(unsigned short), 4);
  }
  static QTypedArrayData *sharedNull()
  {
    return static_cast<QTypedArrayData *>(QArrayData::sharedNull());
  }
};
typedef QTypedArrayData QStringData;
class QString
{
public: typedef QStringData Data;
  inline QString();
  inline QString(const QString &);
  inline ~QString();
  inline QString &operator=(QString &&other)
  {
    std::swap(d, other.d);
    return *this;
  }
  static inline QString fromUtf8(const char *str, int size = -1)
  {
    return fromUtf8_helper(str, size);
  }
  inline QString(const char *ch) : d(fromAscii_helper(ch, ch ? int(strlen(ch)) 
: -1))
  {
  }
  inline QString &operator=(const char *ch)
  {
    return (*this = fromUtf8(ch));
  }
private: Data *d;
  static Data *fromAscii_helper(const char *str, int size = -1);
  static QString fromUtf8_helper(const char *str, int size);
};
inline QString::QString(const QString &other) : d(other.d)
{
  d->ref.ref();
}
inline QString::QString() : d(Data::sharedNull())
{
}
inline QString::~QString()
{
  if (!d->ref.deref()) Data::deallocate(d);
}
struct QListData
{
  struct Data
  {
  };
  static const Data shared_null;
};
class QList
{
  QListData::Data *d;
public: inline QList() : d(const_cast<QListData::Data 
*>(&QListData::shared_null))
  {
  }
};
struct QHashData
{
  struct Node
  {
  };
  Node **buckets;
  QR ref;
  int size;
  short numBits;
  int numBuckets;
  void *allocateNode(int nodeAlign);
  QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void 
(*node_delete)(Node *), int nodeSize, int nodeAlign);
  bool willGrow();
  void rehash(int hint);
  void free_helper(void (*node_delete)(Node *));
  static const QHashData shared_null;
};
inline bool QHashData::willGrow()
{
  if (size >= numBuckets)
    {
      rehash(numBits + 1);
      return true;
    }
  return false;
}
template <class Key, class T> struct QHashNode
{
  QHashNode *next;
  const unsigned int h;
  const Key key;
  T value;
  inline QHashNode(const Key &key0, const T &value0, unsigned int hash, 
QHashNode *n) : next(n), h(hash), key(key0), value(value0)
  {
  }
};
template <class Key, class T> struct QHashDummyNode
{
};
template <class Key, class T> class QHash
{
  typedef QHashNode<Key, T> Node;
  union
  {
    QHashData *d;
    QHashNode<Key, T> *e;
  };
  static inline int alignOfNode()
  {
    return 4;
  }
public: inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null))
  {
  }
  inline void detach()
  {
    if (d->ref.isShared()) detach_helper();
  }
  T &operator[](const Key &key);
private: void detach_helper();
  void freeData(QHashData *d);
  Node **findNode(const Key &key, unsigned int *hp = 0) const;
  Node *createNode(unsigned int h, const Key &key, const T &value, Node 
**nextNode);
  static void deleteNode2(QHashData::Node *node);
  static void duplicateNode(QHashData::Node *originalNode, void *newNode);
};
template <class Key, class T> inline typename QHash<Key, T>::Node * QHash<Key, 
T>::createNode(unsigned int ah, const Key &akey, const T &avalue, Node 
**anextNode)
{
  Node *node;
  node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, 
*anextNode);
  ++d->size;
  return node;
}
template <class Key, class T> void QHash<Key, T>::freeData(QHashData *x)
{
  x->free_helper(deleteNode2);
}
template <class Key, class T> void QHash<Key, T>::detach_helper()
{
  QHashData *x = d->detach_helper(duplicateNode, deleteNode2, sizeof(Node), 
alignOfNode());
  if (!d->ref.deref()) freeData(d);
  d = x;
}
template <class Key, class T> inline T &QHash<Key, T>::operator[](const Key 
&akey)
{
  detach();
  unsigned int h;
  Node **node = findNode(akey, &h);
  if (*node == e)
    {
      if (d->willGrow()) node = findNode(akey, &h);
      return createNode(h, akey, T(), node)->value;
    }
  return (*node)->value;
}
class QStringList : public QList
{
};
class Lclass
{
public: Lclass();
};
class Qclass
{
public: Qclass();
private: bool s;
  QStringList a, b;
  Lclass c;
  QHash<QString,QString> ch;
};
Qclass::Qclass() : s(false)
{
  ch["abc"] = "#!";
  ch["de"] = "#!";
  ch["fghi"] = "<!--";
  ch["jkl"] = "<!--";
  ch["mn"] = "<!--";
  ch["op"] = "<!--";
}

Reply via email to