防止两个对象内部出现混叠



我有一个类似于这个的函数签名

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

在内部,矩阵类具有表示m x n分量的float* data;。我想告诉编译器,ab不会对out矩阵进行别名,因此它不会进行大量的加载存储。

我该怎么做呢?我知道我可以传入指向函数签名的指针,并用__restrict(在MSVC中)标记指针,但我希望保留引用传递对象的习惯用法,即对象包含指向内存的指针。

我还知道__restrict不适用于对象引用。

根据优化器的工作方式,顶部的assert(&in1 != &out && &in2 != &out)可能会起作用。您也可以去掉out参数,并相信优化器会去掉多余的副本(当然,假设它是一个纯out参数)。如果代码是内联的候选代码,编译器可能会发现它自己没有任何别名。如果restrict真的不能处理引用参数,那么可以为函数调用增加一个级别,并将这三个级别都传递给第二个接受适当限制的指针的函数。希望它能为您内联。

编写一个非导出的(文件-staticprivate)乘法函数,该函数接受float*参数,并用restrict标记参数。使Multiply调用此函数。

由于您似乎对__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"中,但我发现上面的更干净。

让宏包装器在编译时具有__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);

最新更新