我想知道在哪些条件下可以优化嵌套循环的不变部分。
为此,我编写了两个函数,其中一个函数实现了三个嵌套循环的分解,而另一个函数没有。
非分解函数如下:
svg.objectCaching = true;
svg.globalCompositeOperation = 'source-atop';
const cols = ["red","green","blue","yellow","black","orange"];
var colCount = 0;
setInterval(()=>{
svg.paths.forEach(p=>{ p.fill = cols[colCount % cols.length] })
colCount += 1;
svg.dirty = true;
canvas.renderAll();
},500)
虽然分解函数是:
template<int k>
double __attribute__ ((noinline)) evaluate(const double u[], const double phi[])
{
double f = 0.;
for (int i3 = 0;i3<k;++i3)
for (int i2 = 0;i2<k;++i2)
for (int i1 = 0;i1<k;++i1)
f += u[i1+k*(i2+k*i3)] * phi[i1] * phi[i2] * phi[i3];
return f;
}
我打电话给以下主要内容:
template<int k>
double __attribute__ ((noinline)) evaluate_fact(const double u[], const double phi[])
{
double f3 = 0.;
for (int i3 = 0;i3<k;++i3)
{
double f2 = 0.;
for (int i2 = 0;i2<k;++i2)
{
double f1 = 0.;
for (int i1 = 0;i1<k;++i1)
{
f1 += u[i1+k*(i2+k*i3)] * phi[i1];
}
f2 += f1 * phi[i2];
}
f3 += f2 * phi[i3];
}
return f3;
}
对于小k,两个函数都生成相同的汇编代码,但在某个大小k~ = 10之后,程序集看起来不再相同,并且callgrind显示在非因子化版本中执行的操作更多。
我应该如何编写代码(如果可能的话),或者我应该告诉GCC如何将evaluate()优化为evaluate_fact()???
我正在使用GCC 7.1.0。 with flags -Ofast -fmove-loop-invariants
使用-funroll-loops没有帮助,除非我添加--param max-fully -pened-insns = 10000 --param max-fully-peel-times = 10000但这是一个完全不同的东西,因为它基本上是展开一切,装配很广泛。
使用-fassociative-math也无济于事。
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/kernel_tests/parsing_ops_test.py#L954声称:“传统的循环不变代码运动,通常由通用编译器应用,仅检查最内层循环的不变性。”这适用于我的代码吗?
谢谢!