1 // PR optimization/12340 2 // Origin: Richard Guenther <richard.guenther (at) uni-tuebingen.de> 3 // Testcase by Eric Botcazou <ebotcazou (at) 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 14 inline void* operator new(size_t, void* __p) throw() { return __p; } 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 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 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 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 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 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 101 class Interval : public Domain<DomainTraits<Interval> > 102 { 103 public: 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 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 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 134 template<> 135 struct 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 145 class Loc : public Domain<DomainTraits<Loc> > 146 { 147 public: 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 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 172 class RefCounted 173 { 174 public: 175 RefCounted() : count_m(0) {} 176 177 void addReference() { ++count_m; } 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: 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 222 private: 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 273 class DataBlockController : public RefBlockController 274 { 275 public: 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 285 private: 286 mutable char *dataObjectPtr_m; 287 bool owned_m; 288 }; 289 290 class RefCountedPtr 291 { 292 public: 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 302 private: 303 friend class RefCountedBlockPtr; 304 DataBlockController * ptr_m; 305 }; 306 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: 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 336 protected: 337 int offset_m; 338 RefCountedPtr blockControllerPtr_m; 339 }; 340 341 class DataBlockPtr : public RefCountedBlockPtr 342 { 343 public: 344 explicit DataBlockPtr(unsigned int size) : RefCountedBlockPtr(size) {} 345 }; 346 347 class Node 348 { 349 public: 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 355 private: 356 Interval domain_m; 357 Interval allocated_m; 358 }; 359 360 class DomainLayout 361 { 362 public: 363 explicit DomainLayout(const Interval &dom) : node_m(0, dom) {} 364 365 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 379 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 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: 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 405 private: 406 DataBlockPtr dataBlock_m; 407 double *data_m; 408 }; 409 410 int 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