1// PR optimization/12340
2// Origin: Richard Guenther <richard.guenther@uni-tuebingen.de>
3// Testcase by Eric Botcazou <ebotcazou@libertysurf.fr>
4
5// This used to segfault on x86 because the loop optimizer wrongly
6// interpreted a double assignment to a biv as a double increment,
7// which subsequently fooled the unroller.
8
9// { dg-do run }
10// { dg-options "-O2 -fno-exceptions -funroll-loops" }
11
12typedef __SIZE_TYPE__ size_t;
13
14inline void* operator new(size_t, void* __p) throw() { return __p; }
15inline void operator delete (void*, void*) throw() { };
16
17class Loc;
18class Interval;
19
20template<class DT>
21class DomainBase
22{
23public:
24  typedef typename DT::Domain_t Domain_t;
25  typedef typename DT::Storage_t Storage_t;
26
27  Domain_t &unwrap() { return *static_cast<Domain_t *>(this); }
28
29  const Domain_t &unwrap() const {
30    return *static_cast<Domain_t *>(const_cast<DomainBase<DT> *>(this));
31  }
32
33protected:
34  Storage_t domain_m;
35};
36
37template<class DT>
38class Domain : public DomainBase<DT>
39{
40  typedef DomainBase<DT> Base_t;
41
42public:
43  typedef typename DT::Size_t Size_t;
44  typedef typename DT::Element_t Element_t;
45  typedef typename Base_t::Domain_t Domain_t;
46  typedef typename Base_t::Storage_t Storage_t;
47
48  Domain_t &operator[](int) { return this->unwrap(); }
49
50  const Domain_t &operator[](int) const { return this->unwrap(); }
51
52  template<class T>
53  void setDomain(const T &newdom) {
54    DT::setDomain(this->domain_m, newdom);
55  }
56
57  Element_t first() const { return DT::first(this->domain_m); }
58
59  Size_t length() const { return DT::length(this->domain_m); }
60
61  Size_t size() const { return length(); }
62};
63
64template<class T>
65struct DomainTraits;
66
67template<>
68struct DomainTraits<Interval>
69{
70  typedef int Size_t;
71  typedef int Element_t;
72  typedef Interval Domain_t;
73  typedef Interval OneDomain_t;
74  typedef Loc AskDomain_t;
75  typedef int Storage_t[2];
76  enum { dimensions = 1 };
77  enum { wildcard = false };
78
79  static int first(const Storage_t &d) { return d[0]; }
80
81  static int length(const Storage_t &d) { return d[1]; }
82
83  static OneDomain_t &getDomain(Domain_t &d, int) { return d; }
84
85  static const OneDomain_t &getDomain(const Domain_t &d, int) { return d; }
86
87  template<class T>
88  static void setDomain(Storage_t &dom, const T &newdom) {
89    dom[0] = newdom.first();
90    dom[1] = newdom.length();
91  }
92
93  template<class T1, class T2>
94  static void setDomain(Storage_t &dom, const T1 &begval, const T2 &endval) {
95    dom[0] = begval;
96    dom[1] = (endval - begval + 1);
97  }
98
99};
100
101class Interval : public Domain<DomainTraits<Interval> >
102{
103public:
104  Interval(const Interval &a) : Domain<DomainTraits<Interval> >() {
105    for (int i=0; i < DomainTraits<Interval>::dimensions; ++i)
106      DomainTraits<Interval>::getDomain(*this, i).setDomain(
107                                DomainTraits<Interval>::getDomain(a, i));
108  }
109
110  Interval(int a) : Domain<DomainTraits<Interval> >()
111  {
112    DomainTraits<Interval>::setDomain(domain_m, 0, a - 1);
113  }
114};
115
116template<>
117struct DomainTraits<Loc>
118{
119  typedef int Size_t;
120  typedef int Element_t;
121  typedef Loc Domain_t;
122  typedef Loc AskDomain_t;
123  typedef Loc MultResult_t;
124  typedef int Storage_t;
125
126  static int first(int d) { return d; }
127
128  template<class T>
129  static void setDomain(int &dom, const T &newdom) {
130    dom = DomainTraits<T>::getFirst(newdom);
131  }
132};
133
134template<>
135struct DomainTraits<int>
136 {
137  enum { dimensions = 1 };
138  enum { wildcard = false };
139
140  static int getPointDomain(int d, int) { return d; }
141
142  static int getFirst(const int &d) { return d; }
143};
144
145class Loc : public Domain<DomainTraits<Loc> >
146{
147public:
148  explicit Loc(const int &a) : Domain<DomainTraits<Loc> >() {
149    for (int i=0; i < 1; ++i)
150      (*this)[i].setDomain(DomainTraits<int>::getPointDomain(a, 0));
151  }
152};
153
154struct ElementProperties
155{
156  enum { hasTrivialDefaultConstructor = false };
157  enum { hasTrivialDestructor = false };
158
159  static void construct(double* addr)
160  {
161    new (addr) double();
162  }
163
164  static void construct(double* addr, const double& model)
165  {
166    new (addr) double(model);
167  }
168
169  static void destruct(double *addr) {}
170};
171
172class RefCounted
173{
174public:
175  RefCounted() : count_m(0) {}
176
177  void addReference() { ++count_m; }
178  bool removeRefAndCheckGarbage()
179  {
180    return (--count_m == 0);
181  }
182
183private:
184  int count_m;
185};
186
187class RefBlockController : public RefCounted
188{
189public:
190  explicit RefBlockController(unsigned int size)
191    : pBegin_m(0), pEnd_m(0), pEndOfStorage_m(0), dealloc_m(false)
192  {
193    reallocateStorage(size, false);
194
195    if (!ElementProperties::hasTrivialDefaultConstructor)
196      {
197        for (double * pt = begin(); pt != end(); ++pt)
198          ElementProperties::construct(pt);
199      }
200  }
201
202  ~RefBlockController()
203  {
204    deleteStorage();
205  }
206
207  double *begin() const
208  {
209    return pBegin_m;
210  }
211
212  double *end() const
213  {
214    return pEnd_m;
215  }
216
217  bool isMine() const
218  {
219    return dealloc_m;
220  }
221
222private:
223  void deleteStorage()
224  {
225    if (isMine() && pBegin_m != 0)
226      {
227        if (!ElementProperties::hasTrivialDestructor)
228          for (double *pt = begin(); pt != end(); ++pt)
229            ElementProperties::destruct(pt);
230
231        char *tmp = reinterpret_cast<char *>(pBegin_m);
232        delete [] tmp;
233      }
234  }
235
236  void reallocateStorage(unsigned int newsize, bool copyold = false)
237  {
238    double *pBeginNew = 0;
239    double *pEndNew = 0;
240    double *pEndOfStorageNew = 0;
241
242    if (newsize > 0)
243      {
244        int nsize = newsize * sizeof(double);
245        char *tmp = new char[nsize];
246        pBeginNew = reinterpret_cast<double *>(tmp);
247        pEndNew = pBeginNew + newsize;
248        pEndOfStorageNew = pBeginNew + (nsize / sizeof(double));
249
250        if (copyold)
251          {
252            double * pOld = begin();
253            double * pNew = pBeginNew;
254            while (pOld != end() && pNew != pEndNew)
255              ElementProperties::construct(pNew++,*pOld++);
256          }
257      }
258
259    deleteStorage();
260
261    pBegin_m = pBeginNew;
262    pEnd_m = pEndNew;
263    pEndOfStorage_m = pEndOfStorageNew;
264    dealloc_m = true;
265  }
266
267  double *pBegin_m;
268  double *pEnd_m;
269  double *pEndOfStorage_m;
270  bool dealloc_m;
271};
272
273class DataBlockController : public RefBlockController
274{
275public:
276  explicit
277  DataBlockController(unsigned int size)
278    : RefBlockController(size), dataObjectPtr_m(new char), owned_m(true) {}
279
280  ~DataBlockController()
281  {
282    if (owned_m) delete dataObjectPtr_m;
283  }
284
285private:
286  mutable char *dataObjectPtr_m;
287  bool owned_m;
288};
289
290class RefCountedPtr
291{
292public:
293  RefCountedPtr(DataBlockController * const pT) : ptr_m(pT)
294    { if (isValid()) ptr_m->addReference(); }
295
296  ~RefCountedPtr() { invalidate(); }
297
298  DataBlockController* operator->() const { return ptr_m; }
299  void invalidate();
300  bool isValid() const { return ptr_m != 0; }
301
302private:
303  friend class RefCountedBlockPtr;
304  DataBlockController * ptr_m;
305};
306
307inline void RefCountedPtr::invalidate()
308{
309  if ( isValid() && ptr_m->removeRefAndCheckGarbage() )
310    delete ptr_m;
311  ptr_m = 0;
312}
313
314class RefCountedBlockPtr
315{
316public:
317  explicit RefCountedBlockPtr(unsigned int size)
318    : offset_m(0),
319      blockControllerPtr_m(new DataBlockController(size)) {}
320
321  int offset() const
322  {
323    return offset_m;
324  }
325
326  double *beginPointer() const
327  {
328    return blockControllerPtr_m->begin();
329  }
330
331  double *currentPointer() const
332  {
333    return beginPointer() + offset();
334  }
335
336protected:
337  int offset_m;
338  RefCountedPtr blockControllerPtr_m;
339};
340
341class DataBlockPtr : public RefCountedBlockPtr
342{
343public:
344  explicit DataBlockPtr(unsigned int size) : RefCountedBlockPtr(size) {}
345};
346
347class Node
348{
349public:
350  Node(const Interval &owned, const Interval &allocated)
351    : domain_m(owned), allocated_m(allocated) {}
352
353  const Interval &allocated() const { return allocated_m; }
354
355private:
356  Interval domain_m;
357  Interval allocated_m;
358};
359
360class DomainLayout
361{
362public:
363  explicit DomainLayout(const Interval &dom) : node_m(0, dom) {}
364
365  const Interval &domain() const
366  {
367    return node_m.allocated();
368  }
369
370private:
371  Node node_m;
372};
373
374class BrickBase
375{
376public:
377  explicit BrickBase(const Interval &domain);
378
379  int offset(const Loc &dom) const { return off_m + dom[0].first(); }
380
381protected:
382  DomainLayout layout_m;
383  int firsts_m;
384  int off_m;
385};
386
387BrickBase::BrickBase(const Interval &dom)
388  : layout_m(dom)
389{
390  firsts_m = layout_m.domain()[0].first();
391  off_m = -firsts_m;
392}
393
394class Engine : public BrickBase
395{
396public:
397  explicit Engine(const Interval &dom)
398  : BrickBase(dom), dataBlock_m(dom.size()), data_m(dataBlock_m.currentPointer()) {}
399
400  double& operator()(const Loc &loc) const
401  {
402    return data_m[this->offset(loc)];
403  }
404
405private:
406  DataBlockPtr dataBlock_m;
407  double *data_m;
408};
409
410
411int main()
412{
413  Interval I(10);
414  Engine A(I);
415
416  for (int i = 0; i < 10; i++)
417    A(Loc(i)) = 2.0 + i - i*i;
418
419  return 0;
420}
421