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
12 typedef __SIZE_TYPE__ size_t;
13
operator new(size_t,void * __p)14 inline void* operator new(size_t, void* __p) throw() { return __p; }
operator delete(void *,void *)15 inline void operator delete (void*, void*) throw() { };
16
17 class Loc;
18 class Interval;
19
20 template<class DT>
21 class DomainBase
22 {
23 public:
24 typedef typename DT::Domain_t Domain_t;
25 typedef typename DT::Storage_t Storage_t;
26
unwrap()27 Domain_t &unwrap() { return *static_cast<Domain_t *>(this); }
28
unwrap() const29 const Domain_t &unwrap() const {
30 return *static_cast<Domain_t *>(const_cast<DomainBase<DT> *>(this));
31 }
32
33 protected:
34 Storage_t domain_m;
35 };
36
37 template<class DT>
38 class Domain : public DomainBase<DT>
39 {
40 typedef DomainBase<DT> Base_t;
41
42 public:
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
operator [](int)48 Domain_t &operator[](int) { return this->unwrap(); }
49
operator [](int) const50 const Domain_t &operator[](int) const { return this->unwrap(); }
51
52 template<class T>
setDomain(const T & newdom)53 void setDomain(const T &newdom) {
54 DT::setDomain(this->domain_m, newdom);
55 }
56
first() const57 Element_t first() const { return DT::first(this->domain_m); }
58
length() const59 Size_t length() const { return DT::length(this->domain_m); }
60
size() const61 Size_t size() const { return length(); }
62 };
63
64 template<class T>
65 struct DomainTraits;
66
67 template<>
68 struct 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
firstDomainTraits79 static int first(const Storage_t &d) { return d[0]; }
80
lengthDomainTraits81 static int length(const Storage_t &d) { return d[1]; }
82
getDomainDomainTraits83 static OneDomain_t &getDomain(Domain_t &d, int) { return d; }
84
getDomainDomainTraits85 static const OneDomain_t &getDomain(const Domain_t &d, int) { return d; }
86
87 template<class T>
setDomainDomainTraits88 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>
setDomainDomainTraits94 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
101 class Interval : public Domain<DomainTraits<Interval> >
102 {
103 public:
Interval(const Interval & a)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
Interval(int a)110 Interval(int a) : Domain<DomainTraits<Interval> >()
111 {
112 DomainTraits<Interval>::setDomain(domain_m, 0, a - 1);
113 }
114 };
115
116 template<>
117 struct 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
firstDomainTraits126 static int first(int d) { return d; }
127
128 template<class T>
setDomainDomainTraits129 static void setDomain(int &dom, const T &newdom) {
130 dom = DomainTraits<T>::getFirst(newdom);
131 }
132 };
133
134 template<>
135 struct DomainTraits<int>
136 {
137 enum { dimensions = 1 };
138 enum { wildcard = false };
139
getPointDomainDomainTraits140 static int getPointDomain(int d, int) { return d; }
141
getFirstDomainTraits142 static int getFirst(const int &d) { return d; }
143 };
144
145 class Loc : public Domain<DomainTraits<Loc> >
146 {
147 public:
Loc(const int & a)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
154 struct ElementProperties
155 {
156 enum { hasTrivialDefaultConstructor = false };
157 enum { hasTrivialDestructor = false };
158
constructElementProperties159 static void construct(double* addr)
160 {
161 new (addr) double();
162 }
163
constructElementProperties164 static void construct(double* addr, const double& model)
165 {
166 new (addr) double(model);
167 }
168
destructElementProperties169 static void destruct(double *addr) {}
170 };
171
172 class RefCounted
173 {
174 public:
RefCounted()175 RefCounted() : count_m(0) {}
176
addReference()177 void addReference() { ++count_m; }
removeRefAndCheckGarbage()178 bool removeRefAndCheckGarbage()
179 {
180 return (--count_m == 0);
181 }
182
183 private:
184 int count_m;
185 };
186
187 class RefBlockController : public RefCounted
188 {
189 public:
RefBlockController(unsigned int size)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
~RefBlockController()202 ~RefBlockController()
203 {
204 deleteStorage();
205 }
206
begin() const207 double *begin() const
208 {
209 return pBegin_m;
210 }
211
end() const212 double *end() const
213 {
214 return pEnd_m;
215 }
216
isMine() const217 bool isMine() const
218 {
219 return dealloc_m;
220 }
221
222 private:
deleteStorage()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
reallocateStorage(unsigned int newsize,bool copyold=false)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
273 class DataBlockController : public RefBlockController
274 {
275 public:
276 explicit
DataBlockController(unsigned int size)277 DataBlockController(unsigned int size)
278 : RefBlockController(size), dataObjectPtr_m(new char), owned_m(true) {}
279
~DataBlockController()280 ~DataBlockController()
281 {
282 if (owned_m) delete dataObjectPtr_m;
283 }
284
285 private:
286 mutable char *dataObjectPtr_m;
287 bool owned_m;
288 };
289
290 class RefCountedPtr
291 {
292 public:
RefCountedPtr(DataBlockController * const pT)293 RefCountedPtr(DataBlockController * const pT) : ptr_m(pT)
294 { if (isValid()) ptr_m->addReference(); }
295
~RefCountedPtr()296 ~RefCountedPtr() { invalidate(); }
297
operator ->() const298 DataBlockController* operator->() const { return ptr_m; }
299 void invalidate();
isValid() const300 bool isValid() const { return ptr_m != 0; }
301
302 private:
303 friend class RefCountedBlockPtr;
304 DataBlockController * ptr_m;
305 };
306
invalidate()307 inline void RefCountedPtr::invalidate()
308 {
309 if ( isValid() && ptr_m->removeRefAndCheckGarbage() )
310 delete ptr_m;
311 ptr_m = 0;
312 }
313
314 class RefCountedBlockPtr
315 {
316 public:
RefCountedBlockPtr(unsigned int size)317 explicit RefCountedBlockPtr(unsigned int size)
318 : offset_m(0),
319 blockControllerPtr_m(new DataBlockController(size)) {}
320
offset() const321 int offset() const
322 {
323 return offset_m;
324 }
325
beginPointer() const326 double *beginPointer() const
327 {
328 return blockControllerPtr_m->begin();
329 }
330
currentPointer() const331 double *currentPointer() const
332 {
333 return beginPointer() + offset();
334 }
335
336 protected:
337 int offset_m;
338 RefCountedPtr blockControllerPtr_m;
339 };
340
341 class DataBlockPtr : public RefCountedBlockPtr
342 {
343 public:
DataBlockPtr(unsigned int size)344 explicit DataBlockPtr(unsigned int size) : RefCountedBlockPtr(size) {}
345 };
346
347 class Node
348 {
349 public:
Node(const Interval & owned,const Interval & allocated)350 Node(const Interval &owned, const Interval &allocated)
351 : domain_m(owned), allocated_m(allocated) {}
352
allocated() const353 const Interval &allocated() const { return allocated_m; }
354
355 private:
356 Interval domain_m;
357 Interval allocated_m;
358 };
359
360 class DomainLayout
361 {
362 public:
DomainLayout(const Interval & dom)363 explicit DomainLayout(const Interval &dom) : node_m(0, dom) {}
364
domain() const365 const Interval &domain() const
366 {
367 return node_m.allocated();
368 }
369
370 private:
371 Node node_m;
372 };
373
374 class BrickBase
375 {
376 public:
377 explicit BrickBase(const Interval &domain);
378
offset(const Loc & dom) const379 int offset(const Loc &dom) const { return off_m + dom[0].first(); }
380
381 protected:
382 DomainLayout layout_m;
383 int firsts_m;
384 int off_m;
385 };
386
BrickBase(const Interval & dom)387 BrickBase::BrickBase(const Interval &dom)
388 : layout_m(dom)
389 {
390 firsts_m = layout_m.domain()[0].first();
391 off_m = -firsts_m;
392 }
393
394 class Engine : public BrickBase
395 {
396 public:
Engine(const Interval & dom)397 explicit Engine(const Interval &dom)
398 : BrickBase(dom), dataBlock_m(dom.size()), data_m(dataBlock_m.currentPointer()) {}
399
operator ()(const Loc & loc) const400 double& operator()(const Loc &loc) const
401 {
402 return data_m[this->offset(loc)];
403 }
404
405 private:
406 DataBlockPtr dataBlock_m;
407 double *data_m;
408 };
409
410 int
main()411 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