我有一个类似于这个的函数签名
void Mutliply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);
在内部,矩阵类具有表示m x n
分量的float* data;
。我想告诉编译器,a
和b
不会对out矩阵进行别名,因此它不会进行大量的加载存储。
我该怎么做呢?我知道我可以传入指向函数签名的指针,并用__restrict
(在MSVC中)标记指针,但我希望保留引用传递对象的习惯用法,即对象包含指向内存的指针。
我还知道__restrict
不适用于对象引用。
根据优化器的工作方式,顶部的assert(&in1 != &out && &in2 != &out)
可能会起作用。您也可以去掉out参数,并相信优化器会去掉多余的副本(当然,假设它是一个纯out参数)。如果代码是内联的候选代码,编译器可能会发现它自己没有任何别名。如果restrict
真的不能处理引用参数,那么可以为函数调用增加一个级别,并将这三个级别都传递给第二个接受适当限制的指针的函数。希望它能为您内联。
编写一个非导出的(文件-static
,private
)乘法函数,该函数接受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);