优化嵌套循环以填充阵列,以帮助编译器产生有效的ARM汇编?

问题描述 投票:2回答:2

我刚刚获得了重新编写以下C函数的任务,以帮助ARM编译器生成更有效的汇编代码。有人知道该怎么做吗?

void some_function(int *data)
{
    int  i, j;

    for (i = 0; i < 64; i++)
    {
        for (j = 0; j < 64; j++)
            data[j + 64*i] = (i + j)/2;
    }
}
c assembly arm micro-optimization
2个回答
2
投票

首先(如乔纳森·莱夫勒所说,编译器可能已经做得很好,以至于试图通过编写特定的C代码来进行优化通常在商业上有问题,即,与通过稍微快一点的代码所能赚到的相比,您在开发时间上损失的钱更多。 。但是有时候这是值得的;让我们假设是这种情况。

如果您感到乐观,请在测量时这样做。编写最终不太理想的代码是很有可能的,因为以微妙的方式,否则可能的编译器优化就被挫败了。另外,是否进行优化以及进行多少优化取决于环境,即必须在所有潜在环境中进行测量。

好吧,经过那次明智的破解之后,我在其中的代码中演示了注释中建议的优化,其中之一是乔纳森·莱弗勒(Jonathan Leffler:]]

/* Jonathan Leffler */
void some_function(int *data)
{
    int  i, j;
    int  k = 0;

    for (i = 0; i < 64; i++)
    {
        for (j = 0; j < 64; j++)
        {
            data[k++] = (i + j)/2;
        }
    }
}

/* Yunnosch 1, loop unrolling by 2 */
void some_function(int *data)
{
    int  i, j;

    for (i = 0; i < 64; i++)
    {
        for (j = 0; j < 64; j+=2)
            data[j +     64*i] = (i + j  )/2;
            data[j + 1 + 64*i] = (i + j+1)/2;
    }
}

/* Yunnosch 1 and Jonathan Leffler */
void some_function(int *data)
{
    int  i, j;
    int k=0; /* Jonathan Leffler */

    for (i = 0; i < 64; i++)
    {
        for (j = 0; j < 64; j+=2) /* Yunnosch */
        {
            data[k++] = (i + j  )/2;
            data[k++] = (i + j+1)/2; /* Yunnosch */
        }
    }
}

/* Yunnosch 2, avoiding the /2, including Jonathan Leffler */
/* Well, duh. This is harder than I thought... 
   I admit that this is NOT tested, I want to demonstrate the idea.
   Everybody feel free to help the very grateful me with fixing errors. */
void some_function(int *data)
{
    int  i, j;
    int  k=0;

    for (i = 0; i < 32; i++) /* magic numbers I normally avoid, 32 is 64/2 */
    {
        for (j = 0; j < 32; j++)
        {
            data[k     ] = (i + j);
            data[k+1   ] = (i + j);
            data[k  +64] = (i + j);
            data[k+1+64] = (i + j +1);
            k+=2;
        }
        k+=64;
    }
}

最新版本是基于以下可观察到的2x2组模式,具有预期的结果,如2D解释所示:

00 11 ...
01 12 ...

11 22 ...
12 23 ...
.. ..
.. ..
.. ..
´´´´


0
投票

优化C代码以为特定的编译器/处理器生成“更有效的汇编代码”是您通常不应该做的事情。编写清晰易懂的C代码,并让编译器进行优化。

即使您使用C代码进行了各种技巧,并最终为特定的编译器/处理器获得了“更高效的汇编代码”,事实证明,简单的编译器升级可能会破坏整个过程,您将再次更改C代码。

对于像您的代码一样简单的内容,请从头开始用汇编代码编写。但是请注意,您必须是该处理器/汇编语言的真正专家才能击败像样的编译器。

无论如何...如果我们想猜测,这是我的猜测:

void some_function(int *data)
{
    int  i, j, x;

    for (i = 0; i < 64; i++)
    {
        // Handle even i-values
        x = i/2;
        for (j = 0; j < 64; j += 2)
        {
            *data = x;
            ++data;
            *data = x;
            ++data;
            ++x;        // Increment after writing to data twice
        }

        ++i;

        // Handle odd i-values
        x = i/2;
        for (j = 0; j < 64; j += 2)
        {
            *data = x;
            ++data;
            ++x;        // Increment after writing to data once
            *data = x;
            ++data;
        }
    }
}

这个想法是1)用指针增量替换数组索引,以及2)用增量替换(i+j)/2

我已经没有做过任何测量,所以不能肯定地说这将是一个很好的解决方案。我将其留给OP。


与上述相同,但还有一些调整

void some_function(int *data)
{
    for (int i = 0; i < 32; i++)
    {
        // when i is even, the output is in matched pairs
        int value = i;
        for (int j = 0; j < 32; j++)
        {
            *data++ = value;
            *data++ = value++;
        }

        // when i is odd, the output starts with a singleton
        // followed by matched pairs, and ending with a singleton
        value = i;
        *data++ = value++;
        for (int j = 0; j < 31; j++)
        {
            *data++ = value;
            *data++ = value++;
        }
        *data++ = value;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.