// PR optimization/12340
|
// PR optimization/12340
|
// Origin: Richard Guenther
|
// Origin: Richard Guenther
|
// Testcase by Eric Botcazou
|
// Testcase by Eric Botcazou
|
|
|
// This used to segfault on x86 because the loop optimizer wrongly
|
// This used to segfault on x86 because the loop optimizer wrongly
|
// interpreted a double assignment to a biv as a double increment,
|
// interpreted a double assignment to a biv as a double increment,
|
// which subsequently fooled the unroller.
|
// which subsequently fooled the unroller.
|
|
|
// { dg-do run }
|
// { dg-do run }
|
// { dg-options "-O2 -fno-exceptions -funroll-loops" }
|
// { dg-options "-O2 -fno-exceptions -funroll-loops" }
|
|
|
typedef __SIZE_TYPE__ size_t;
|
typedef __SIZE_TYPE__ size_t;
|
|
|
inline void* operator new(size_t, void* __p) throw() { return __p; }
|
inline void* operator new(size_t, void* __p) throw() { return __p; }
|
inline void operator delete (void*, void*) throw() { };
|
inline void operator delete (void*, void*) throw() { };
|
|
|
class Loc;
|
class Loc;
|
class Interval;
|
class Interval;
|
|
|
template
|
template
|
class DomainBase
|
class DomainBase
|
{
|
{
|
public:
|
public:
|
typedef typename DT::Domain_t Domain_t;
|
typedef typename DT::Domain_t Domain_t;
|
typedef typename DT::Storage_t Storage_t;
|
typedef typename DT::Storage_t Storage_t;
|
|
|
Domain_t &unwrap() { return *static_cast(this); }
|
Domain_t &unwrap() { return *static_cast(this); }
|
|
|
const Domain_t &unwrap() const {
|
const Domain_t &unwrap() const {
|
return *static_cast(const_cast *>(this));
|
return *static_cast(const_cast *>(this));
|
}
|
}
|
|
|
protected:
|
protected:
|
Storage_t domain_m;
|
Storage_t domain_m;
|
};
|
};
|
|
|
template
|
template
|
class Domain : public DomainBase
|
class Domain : public DomainBase
|
{
|
{
|
typedef DomainBase Base_t;
|
typedef DomainBase Base_t;
|
|
|
public:
|
public:
|
typedef typename DT::Size_t Size_t;
|
typedef typename DT::Size_t Size_t;
|
typedef typename DT::Element_t Element_t;
|
typedef typename DT::Element_t Element_t;
|
typedef typename Base_t::Domain_t Domain_t;
|
typedef typename Base_t::Domain_t Domain_t;
|
typedef typename Base_t::Storage_t Storage_t;
|
typedef typename Base_t::Storage_t Storage_t;
|
|
|
Domain_t &operator[](int) { return this->unwrap(); }
|
Domain_t &operator[](int) { return this->unwrap(); }
|
|
|
const Domain_t &operator[](int) const { return this->unwrap(); }
|
const Domain_t &operator[](int) const { return this->unwrap(); }
|
|
|
template
|
template
|
void setDomain(const T &newdom) {
|
void setDomain(const T &newdom) {
|
DT::setDomain(this->domain_m, newdom);
|
DT::setDomain(this->domain_m, newdom);
|
}
|
}
|
|
|
Element_t first() const { return DT::first(this->domain_m); }
|
Element_t first() const { return DT::first(this->domain_m); }
|
|
|
Size_t length() const { return DT::length(this->domain_m); }
|
Size_t length() const { return DT::length(this->domain_m); }
|
|
|
Size_t size() const { return length(); }
|
Size_t size() const { return length(); }
|
};
|
};
|
|
|
template
|
template
|
struct DomainTraits;
|
struct DomainTraits;
|
|
|
template<>
|
template<>
|
struct DomainTraits
|
struct DomainTraits
|
{
|
{
|
typedef int Size_t;
|
typedef int Size_t;
|
typedef int Element_t;
|
typedef int Element_t;
|
typedef Interval Domain_t;
|
typedef Interval Domain_t;
|
typedef Interval OneDomain_t;
|
typedef Interval OneDomain_t;
|
typedef Loc AskDomain_t;
|
typedef Loc AskDomain_t;
|
typedef int Storage_t[2];
|
typedef int Storage_t[2];
|
enum { dimensions = 1 };
|
enum { dimensions = 1 };
|
enum { wildcard = false };
|
enum { wildcard = false };
|
|
|
static int first(const Storage_t &d) { return d[0]; }
|
static int first(const Storage_t &d) { return d[0]; }
|
|
|
static int length(const Storage_t &d) { return d[1]; }
|
static int length(const Storage_t &d) { return d[1]; }
|
|
|
static OneDomain_t &getDomain(Domain_t &d, int) { return d; }
|
static OneDomain_t &getDomain(Domain_t &d, int) { return d; }
|
|
|
static const OneDomain_t &getDomain(const Domain_t &d, int) { return d; }
|
static const OneDomain_t &getDomain(const Domain_t &d, int) { return d; }
|
|
|
template
|
template
|
static void setDomain(Storage_t &dom, const T &newdom) {
|
static void setDomain(Storage_t &dom, const T &newdom) {
|
dom[0] = newdom.first();
|
dom[0] = newdom.first();
|
dom[1] = newdom.length();
|
dom[1] = newdom.length();
|
}
|
}
|
|
|
template
|
template
|
static void setDomain(Storage_t &dom, const T1 &begval, const T2 &endval) {
|
static void setDomain(Storage_t &dom, const T1 &begval, const T2 &endval) {
|
dom[0] = begval;
|
dom[0] = begval;
|
dom[1] = (endval - begval + 1);
|
dom[1] = (endval - begval + 1);
|
}
|
}
|
|
|
};
|
};
|
|
|
class Interval : public Domain >
|
class Interval : public Domain >
|
{
|
{
|
public:
|
public:
|
Interval(const Interval &a) : Domain >() {
|
Interval(const Interval &a) : Domain >() {
|
for (int i=0; i < DomainTraits::dimensions; ++i)
|
for (int i=0; i < DomainTraits::dimensions; ++i)
|
DomainTraits::getDomain(*this, i).setDomain(
|
DomainTraits::getDomain(*this, i).setDomain(
|
DomainTraits::getDomain(a, i));
|
DomainTraits::getDomain(a, i));
|
}
|
}
|
|
|
Interval(int a) : Domain >()
|
Interval(int a) : Domain >()
|
{
|
{
|
DomainTraits::setDomain(domain_m, 0, a - 1);
|
DomainTraits::setDomain(domain_m, 0, a - 1);
|
}
|
}
|
};
|
};
|
|
|
template<>
|
template<>
|
struct DomainTraits
|
struct DomainTraits
|
{
|
{
|
typedef int Size_t;
|
typedef int Size_t;
|
typedef int Element_t;
|
typedef int Element_t;
|
typedef Loc Domain_t;
|
typedef Loc Domain_t;
|
typedef Loc AskDomain_t;
|
typedef Loc AskDomain_t;
|
typedef Loc MultResult_t;
|
typedef Loc MultResult_t;
|
typedef int Storage_t;
|
typedef int Storage_t;
|
|
|
static int first(int d) { return d; }
|
static int first(int d) { return d; }
|
|
|
template
|
template
|
static void setDomain(int &dom, const T &newdom) {
|
static void setDomain(int &dom, const T &newdom) {
|
dom = DomainTraits::getFirst(newdom);
|
dom = DomainTraits::getFirst(newdom);
|
}
|
}
|
};
|
};
|
|
|
template<>
|
template<>
|
struct DomainTraits
|
struct DomainTraits
|
{
|
{
|
enum { dimensions = 1 };
|
enum { dimensions = 1 };
|
enum { wildcard = false };
|
enum { wildcard = false };
|
|
|
static int getPointDomain(int d, int) { return d; }
|
static int getPointDomain(int d, int) { return d; }
|
|
|
static int getFirst(const int &d) { return d; }
|
static int getFirst(const int &d) { return d; }
|
};
|
};
|
|
|
class Loc : public Domain >
|
class Loc : public Domain >
|
{
|
{
|
public:
|
public:
|
explicit Loc(const int &a) : Domain >() {
|
explicit Loc(const int &a) : Domain >() {
|
for (int i=0; i < 1; ++i)
|
for (int i=0; i < 1; ++i)
|
(*this)[i].setDomain(DomainTraits::getPointDomain(a, 0));
|
(*this)[i].setDomain(DomainTraits::getPointDomain(a, 0));
|
}
|
}
|
};
|
};
|
|
|
struct ElementProperties
|
struct ElementProperties
|
{
|
{
|
enum { hasTrivialDefaultConstructor = false };
|
enum { hasTrivialDefaultConstructor = false };
|
enum { hasTrivialDestructor = false };
|
enum { hasTrivialDestructor = false };
|
|
|
static void construct(double* addr)
|
static void construct(double* addr)
|
{
|
{
|
new (addr) double();
|
new (addr) double();
|
}
|
}
|
|
|
static void construct(double* addr, const double& model)
|
static void construct(double* addr, const double& model)
|
{
|
{
|
new (addr) double(model);
|
new (addr) double(model);
|
}
|
}
|
|
|
static void destruct(double *addr) {}
|
static void destruct(double *addr) {}
|
};
|
};
|
|
|
class RefCounted
|
class RefCounted
|
{
|
{
|
public:
|
public:
|
RefCounted() : count_m(0) {}
|
RefCounted() : count_m(0) {}
|
|
|
void addReference() { ++count_m; }
|
void addReference() { ++count_m; }
|
bool removeRefAndCheckGarbage()
|
bool removeRefAndCheckGarbage()
|
{
|
{
|
return (--count_m == 0);
|
return (--count_m == 0);
|
}
|
}
|
|
|
private:
|
private:
|
int count_m;
|
int count_m;
|
};
|
};
|
|
|
class RefBlockController : public RefCounted
|
class RefBlockController : public RefCounted
|
{
|
{
|
public:
|
public:
|
explicit RefBlockController(unsigned int size)
|
explicit RefBlockController(unsigned int size)
|
: pBegin_m(0), pEnd_m(0), pEndOfStorage_m(0), dealloc_m(false)
|
: pBegin_m(0), pEnd_m(0), pEndOfStorage_m(0), dealloc_m(false)
|
{
|
{
|
reallocateStorage(size, false);
|
reallocateStorage(size, false);
|
|
|
if (!ElementProperties::hasTrivialDefaultConstructor)
|
if (!ElementProperties::hasTrivialDefaultConstructor)
|
{
|
{
|
for (double * pt = begin(); pt != end(); ++pt)
|
for (double * pt = begin(); pt != end(); ++pt)
|
ElementProperties::construct(pt);
|
ElementProperties::construct(pt);
|
}
|
}
|
}
|
}
|
|
|
~RefBlockController()
|
~RefBlockController()
|
{
|
{
|
deleteStorage();
|
deleteStorage();
|
}
|
}
|
|
|
double *begin() const
|
double *begin() const
|
{
|
{
|
return pBegin_m;
|
return pBegin_m;
|
}
|
}
|
|
|
double *end() const
|
double *end() const
|
{
|
{
|
return pEnd_m;
|
return pEnd_m;
|
}
|
}
|
|
|
bool isMine() const
|
bool isMine() const
|
{
|
{
|
return dealloc_m;
|
return dealloc_m;
|
}
|
}
|
|
|
private:
|
private:
|
void deleteStorage()
|
void deleteStorage()
|
{
|
{
|
if (isMine() && pBegin_m != 0)
|
if (isMine() && pBegin_m != 0)
|
{
|
{
|
if (!ElementProperties::hasTrivialDestructor)
|
if (!ElementProperties::hasTrivialDestructor)
|
for (double *pt = begin(); pt != end(); ++pt)
|
for (double *pt = begin(); pt != end(); ++pt)
|
ElementProperties::destruct(pt);
|
ElementProperties::destruct(pt);
|
|
|
char *tmp = reinterpret_cast(pBegin_m);
|
char *tmp = reinterpret_cast(pBegin_m);
|
delete [] tmp;
|
delete [] tmp;
|
}
|
}
|
}
|
}
|
|
|
void reallocateStorage(unsigned int newsize, bool copyold = false)
|
void reallocateStorage(unsigned int newsize, bool copyold = false)
|
{
|
{
|
double *pBeginNew = 0;
|
double *pBeginNew = 0;
|
double *pEndNew = 0;
|
double *pEndNew = 0;
|
double *pEndOfStorageNew = 0;
|
double *pEndOfStorageNew = 0;
|
|
|
if (newsize > 0)
|
if (newsize > 0)
|
{
|
{
|
int nsize = newsize * sizeof(double);
|
int nsize = newsize * sizeof(double);
|
char *tmp = new char[nsize];
|
char *tmp = new char[nsize];
|
pBeginNew = reinterpret_cast(tmp);
|
pBeginNew = reinterpret_cast(tmp);
|
pEndNew = pBeginNew + newsize;
|
pEndNew = pBeginNew + newsize;
|
pEndOfStorageNew = pBeginNew + (nsize / sizeof(double));
|
pEndOfStorageNew = pBeginNew + (nsize / sizeof(double));
|
|
|
if (copyold)
|
if (copyold)
|
{
|
{
|
double * pOld = begin();
|
double * pOld = begin();
|
double * pNew = pBeginNew;
|
double * pNew = pBeginNew;
|
while (pOld != end() && pNew != pEndNew)
|
while (pOld != end() && pNew != pEndNew)
|
ElementProperties::construct(pNew++,*pOld++);
|
ElementProperties::construct(pNew++,*pOld++);
|
}
|
}
|
}
|
}
|
|
|
deleteStorage();
|
deleteStorage();
|
|
|
pBegin_m = pBeginNew;
|
pBegin_m = pBeginNew;
|
pEnd_m = pEndNew;
|
pEnd_m = pEndNew;
|
pEndOfStorage_m = pEndOfStorageNew;
|
pEndOfStorage_m = pEndOfStorageNew;
|
dealloc_m = true;
|
dealloc_m = true;
|
}
|
}
|
|
|
double *pBegin_m;
|
double *pBegin_m;
|
double *pEnd_m;
|
double *pEnd_m;
|
double *pEndOfStorage_m;
|
double *pEndOfStorage_m;
|
bool dealloc_m;
|
bool dealloc_m;
|
};
|
};
|
|
|
class DataBlockController : public RefBlockController
|
class DataBlockController : public RefBlockController
|
{
|
{
|
public:
|
public:
|
explicit
|
explicit
|
DataBlockController(unsigned int size)
|
DataBlockController(unsigned int size)
|
: RefBlockController(size), dataObjectPtr_m(new char), owned_m(true) {}
|
: RefBlockController(size), dataObjectPtr_m(new char), owned_m(true) {}
|
|
|
~DataBlockController()
|
~DataBlockController()
|
{
|
{
|
if (owned_m) delete dataObjectPtr_m;
|
if (owned_m) delete dataObjectPtr_m;
|
}
|
}
|
|
|
private:
|
private:
|
mutable char *dataObjectPtr_m;
|
mutable char *dataObjectPtr_m;
|
bool owned_m;
|
bool owned_m;
|
};
|
};
|
|
|
class RefCountedPtr
|
class RefCountedPtr
|
{
|
{
|
public:
|
public:
|
RefCountedPtr(DataBlockController * const pT) : ptr_m(pT)
|
RefCountedPtr(DataBlockController * const pT) : ptr_m(pT)
|
{ if (isValid()) ptr_m->addReference(); }
|
{ if (isValid()) ptr_m->addReference(); }
|
|
|
~RefCountedPtr() { invalidate(); }
|
~RefCountedPtr() { invalidate(); }
|
|
|
DataBlockController* operator->() const { return ptr_m; }
|
DataBlockController* operator->() const { return ptr_m; }
|
void invalidate();
|
void invalidate();
|
bool isValid() const { return ptr_m != 0; }
|
bool isValid() const { return ptr_m != 0; }
|
|
|
private:
|
private:
|
friend class RefCountedBlockPtr;
|
friend class RefCountedBlockPtr;
|
DataBlockController * ptr_m;
|
DataBlockController * ptr_m;
|
};
|
};
|
|
|
inline void RefCountedPtr::invalidate()
|
inline void RefCountedPtr::invalidate()
|
{
|
{
|
if ( isValid() && ptr_m->removeRefAndCheckGarbage() )
|
if ( isValid() && ptr_m->removeRefAndCheckGarbage() )
|
delete ptr_m;
|
delete ptr_m;
|
ptr_m = 0;
|
ptr_m = 0;
|
}
|
}
|
|
|
class RefCountedBlockPtr
|
class RefCountedBlockPtr
|
{
|
{
|
public:
|
public:
|
explicit RefCountedBlockPtr(unsigned int size)
|
explicit RefCountedBlockPtr(unsigned int size)
|
: offset_m(0),
|
: offset_m(0),
|
blockControllerPtr_m(new DataBlockController(size)) {}
|
blockControllerPtr_m(new DataBlockController(size)) {}
|
|
|
int offset() const
|
int offset() const
|
{
|
{
|
return offset_m;
|
return offset_m;
|
}
|
}
|
|
|
double *beginPointer() const
|
double *beginPointer() const
|
{
|
{
|
return blockControllerPtr_m->begin();
|
return blockControllerPtr_m->begin();
|
}
|
}
|
|
|
double *currentPointer() const
|
double *currentPointer() const
|
{
|
{
|
return beginPointer() + offset();
|
return beginPointer() + offset();
|
}
|
}
|
|
|
protected:
|
protected:
|
int offset_m;
|
int offset_m;
|
RefCountedPtr blockControllerPtr_m;
|
RefCountedPtr blockControllerPtr_m;
|
};
|
};
|
|
|
class DataBlockPtr : public RefCountedBlockPtr
|
class DataBlockPtr : public RefCountedBlockPtr
|
{
|
{
|
public:
|
public:
|
explicit DataBlockPtr(unsigned int size) : RefCountedBlockPtr(size) {}
|
explicit DataBlockPtr(unsigned int size) : RefCountedBlockPtr(size) {}
|
};
|
};
|
|
|
class Node
|
class Node
|
{
|
{
|
public:
|
public:
|
Node(const Interval &owned, const Interval &allocated)
|
Node(const Interval &owned, const Interval &allocated)
|
: domain_m(owned), allocated_m(allocated) {}
|
: domain_m(owned), allocated_m(allocated) {}
|
|
|
const Interval &allocated() const { return allocated_m; }
|
const Interval &allocated() const { return allocated_m; }
|
|
|
private:
|
private:
|
Interval domain_m;
|
Interval domain_m;
|
Interval allocated_m;
|
Interval allocated_m;
|
};
|
};
|
|
|
class DomainLayout
|
class DomainLayout
|
{
|
{
|
public:
|
public:
|
explicit DomainLayout(const Interval &dom) : node_m(0, dom) {}
|
explicit DomainLayout(const Interval &dom) : node_m(0, dom) {}
|
|
|
const Interval &domain() const
|
const Interval &domain() const
|
{
|
{
|
return node_m.allocated();
|
return node_m.allocated();
|
}
|
}
|
|
|
private:
|
private:
|
Node node_m;
|
Node node_m;
|
};
|
};
|
|
|
class BrickBase
|
class BrickBase
|
{
|
{
|
public:
|
public:
|
explicit BrickBase(const Interval &domain);
|
explicit BrickBase(const Interval &domain);
|
|
|
int offset(const Loc &dom) const { return off_m + dom[0].first(); }
|
int offset(const Loc &dom) const { return off_m + dom[0].first(); }
|
|
|
protected:
|
protected:
|
DomainLayout layout_m;
|
DomainLayout layout_m;
|
int firsts_m;
|
int firsts_m;
|
int off_m;
|
int off_m;
|
};
|
};
|
|
|
BrickBase::BrickBase(const Interval &dom)
|
BrickBase::BrickBase(const Interval &dom)
|
: layout_m(dom)
|
: layout_m(dom)
|
{
|
{
|
firsts_m = layout_m.domain()[0].first();
|
firsts_m = layout_m.domain()[0].first();
|
off_m = -firsts_m;
|
off_m = -firsts_m;
|
}
|
}
|
|
|
class Engine : public BrickBase
|
class Engine : public BrickBase
|
{
|
{
|
public:
|
public:
|
explicit Engine(const Interval &dom)
|
explicit Engine(const Interval &dom)
|
: BrickBase(dom), dataBlock_m(dom.size()), data_m(dataBlock_m.currentPointer()) {}
|
: BrickBase(dom), dataBlock_m(dom.size()), data_m(dataBlock_m.currentPointer()) {}
|
|
|
double& operator()(const Loc &loc) const
|
double& operator()(const Loc &loc) const
|
{
|
{
|
return data_m[this->offset(loc)];
|
return data_m[this->offset(loc)];
|
}
|
}
|
|
|
private:
|
private:
|
DataBlockPtr dataBlock_m;
|
DataBlockPtr dataBlock_m;
|
double *data_m;
|
double *data_m;
|
};
|
};
|
|
|
|
|
int main()
|
int main()
|
{
|
{
|
Interval I(10);
|
Interval I(10);
|
Engine A(I);
|
Engine A(I);
|
|
|
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
A(Loc(i)) = 2.0 + i - i*i;
|
A(Loc(i)) = 2.0 + i - i*i;
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|