Предотвращение наложения двух внутренних объектов - PullRequest
6 голосов
/ 09 июня 2011

У меня есть функция, похожая на эту

void Mutliply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);

Внутренне класс матрицы имеет float* data;, который представляет m x n компоненты. Я хотел бы сказать компилятору, что a и b не налагают псевдоним на матрицу out, поэтому он не выполняет тонну хранилищ загрузки.

Как бы я поступил так? Я знаю, что мог бы передать указатели на сигнатуру функции и пометить указатели __restrict (в MSVC), но я хотел бы сохранить идиому объекта, передаваемого по ссылке, где объект содержит указатели на память.

Я также знаю, что __restrict не работает с объектными ссылками.

Ответы [ 4 ]

2 голосов
/ 09 июня 2011

В зависимости от того, как работает оптимизатор, assert(&in1 != &out && &in2 != &out) вверху может помочь.Вы также можете избавиться от параметра out и доверить оптимизатору избавление от лишних копий (конечно, при условии, что это чистый параметр out).Если код является кандидатом для встраивания, компилятор может увидеть, что ничего не является псевдонимом сам по себе.Если restrict действительно не работает с опорными параметрами, вы можете иметь дополнительный уровень для вызова функции и передавать все три во вторую функцию, которая правильно принимает указатели.Надеюсь, что это будет сделано для вас.

1 голос
/ 09 июня 2011

Поскольку вам, кажется, удобно работать с указателями __restrict, я бы использовал то, что вы знаете, но вы все еще можете обернуть его и предоставить интерфейс, используя ссылки:

void Multiply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out) {
  if (&a == &b || &a == &out || &b == &out) {
    // indicate precondition violation however you like
    assert(!"precondition violated");
    abort();  // assert isn't always executed
  }
  else {
    DoMultiply(&a, &b, &out);
  }
}

void DoMultiply(MatrixMN const * __restrict a, MatrixMN const * __restrict b,
              MatrixMN * __restrict out)
{
  //...
}

Сделать версию указателя "не публичной"", например, поместив его в пространство имен" details ", присвоив ему внутреннюю связь (не применимо в данном конкретном случае) или присвоив ему специальное имя.Вы могли бы даже использовать локальные переменные вместо параметров и поместить тело функции в «else», но я считаю, что приведенный выше очиститель.

1 голос
/ 09 июня 2011

Напишите неэкспортированную (file- static, private) функцию умножения, которая принимает float* аргументы, пометьте аргументы restrict.Заставьте Multiply вызвать эту функцию.

0 голосов
/ 09 июня 2011

Как насчет макропакета, чтобы иметь эффект __restrict при времени компиляции : (ниже псевдокод, не проверен):

#define Multiply(A,B,C) Multiply_restrict(&A, &B, &C)

Теперь промежуточный метод определяется как,

inline void Multiply_restrict(const MatrixMN* __restrict pA,
            const MatrixMN* __restrict pB, MatrixMN* __restrict pC)
{
  Multiply_(*pA, *pB, *pC);
}

И, наконец, просто добавьте _ после вашего исходного Multiply:

void Mutliply_(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);

Таким образом, конечный эффект будет точно таким же, как вы звоните:

Multiply(x, y, answer);
...