C 从回路上拆下开关

C 从回路上拆下开关,c,gcc,optimization,loop-unrolling,C,Gcc,Optimization,Loop Unrolling,我有一个内部带有开关的循环,看起来像这样(但要复杂得多) for(int i=0;i

我有一个内部带有开关的循环,看起来像这样(但要复杂得多)

for(int i=0;i
consval在编译时未知,但在初始化例程期间已修复。有没有办法在不编译for循环的多个变体的情况下删除switch语句?考虑到x86具有间接分支,应该有一种简单的方法来内联汇编以跳转到我想要的情况,而不是每次迭代都返回循环的顶部。您将如何做到这一点(在gcc中)?最后,这可以在不干扰编译器优化分析的情况下完成。我已经在手动展开循环,但我确信还有很多优化正在进行,我不想破坏它们

据我所知,Julia元编程特性使您能够访问解析器和抽象语法树。结合JIT,您可以解决此类问题。我认为即使没有间接分支的语义,在C中也会有一些合理的解决方法。请注意,Duff的设备不是解决方案,因为我希望在每次循环迭代中返回相同的case语句。这个问题经常出现

编辑

我发现没有条件间接分支x86指令。此外,gcc内联程序集只允许使用固定标签。然而,使用gcc扩展,这仍然可以做到。例如,请参见

这就是为什么。在我的代码中,很难确定是否存在任何性能差异,但在另一台机器上或使用更小更简单的循环时,可能会产生差异

void *forswitch;
switch(ConstVal)
{
case 2: forswitch = &&C; break;
case 1: forswitch = &&B; break;
case 0: forswitch = &&A; break;
}
void *_forswitch[] = {forswitch, &&END_FOR_SWITCH};


i = 0;
{
    v = 0.0;
    C: v += _A[i];
    B: v += _A[i+k];
    A: v += _A[i+j];

    // do some stuff with v

    i += inc;
    forswitch = _forswitch[i==N];
    //forswitch = (i<N)? forswitch: &&END_FOR_SWITCH;
    goto *forswitch;
}

END_FOR_SWITCH:
return;
void*forswitch;
开关(ConstVal)
{
案例2:forswitch=&C;断路;
案例1:forswitch=&B;断路;
情况0:forswitch=&A;中断;
}
void*_forswitch[]={forswitch,&&END_FOR_SWITCH};
i=0;
{
v=0.0;
C:v+=_A[i];
B:v+=_A[i+k];
A:v+=_A[i+j];
//用v做一些事情
i+=公司;
forswitch=_forswitch[i==N];

//forswitch=(iNo,我看不到任何优化switch语句的方法。此外,它也没有那么昂贵。因为没有
break
语句,开关有一种“fall-thru”的趋势。它转换为:

    switch(ConstVal)
    {
    case 2: v= A[i] + A[i+k] + A[i+j]; break;
    case 1: v=        A[i+k] + A[i+j]; break;
    case 0: v=                 A[i+j]; break;
    }
    // do some stuff with v
我不知道如何删除对
consval
的依赖


你可以用3个循环在循环之前进行切换,每个循环对应一个
ConstVal
值,但这肯定看起来像是难看的代码,这取决于
使用v做一些事情的效果。

不,我看不到任何方法来优化switch语句。此外,它没有那么昂贵。因为没有
break
语句中,该开关有“下降通过”的趋势。它转换为:

    switch(ConstVal)
    {
    case 2: v= A[i] + A[i+k] + A[i+j]; break;
    case 1: v=        A[i+k] + A[i+j]; break;
    case 0: v=                 A[i+j]; break;
    }
    // do some stuff with v
我不知道如何删除对
consval
的依赖


你可以在3个循环之前进行切换,每个循环对应一个
ConstVal
值,但这肯定看起来像是难看的代码,这取决于
使用v
做一些事情的效果。

你什么时候知道
ConstVal
,它多久会改变一次?如果你可以重新编译一个小例程并重新链接整个过程,你会发现什么永远不要改变
consval
,那样会解决你的问题

话虽如此,你知道这是个问题吗? 该开关是否负责10%或更多的执行时间? 人们关注非问题是很常见的。 他们知道他们应该“先做个人简介”,但实际上他们并没有这样做。 (这是一个“准备开火瞄准”的案例:


许多人所依赖的一种方法是。

你什么时候知道
ConstVal
,它多久会改变一次?如果你能重新编译一个小例程,并在
ConstVal
改变时重新链接整件事,这将解决你的问题

话虽如此,你知道这是个问题吗? 该开关是否负责10%或更多的执行时间? 人们关注非问题是很常见的。 他们知道他们应该“先做个人简介”,但实际上他们并没有这样做。 (这是一个“准备开火瞄准”的案例:

许多人依赖的一种方法是

有没有办法在不编译for循环的多个变体的情况下删除switch语句

一般来说,最好是做出不同的变体,或者保持原样。但在这种情况下,也许我们可以发明一些技巧。类似的

switch (constVal) {
case 2:
    A1 = A;
    B1 = A + k;
    C1 = A + j;
    break;
case 1:
    A1 = big_zero_array;
    B1 = A + k;
    C1 = A + j;
    break;
case 0:
    A1 = B1 = big_zero_array;
    C1 = A + j
    break;
}

for (int i = 0; i < N; i += inc) {
    v = A1[i] + B1[i] + C1[i];
    //....
}
开关(constVal){
案例2:
A1=A;
B1=A+k;
C1=A+j;
打破
案例1:
A1=大零阵列;
B1=A+k;
C1=A+j;
打破
案例0:
A1=B1=大零阵列;
C1=A+j
打破
}
对于(int i=0;i
不过,这件事需要额外的内存,在某些情况下可能会更慢

有没有办法在不编译for循环的多个变体的情况下删除switch语句

一般来说,最好是做出不同的变体,或者保持原样。但在这种情况下,也许我们可以发明一些技巧。类似的

switch (constVal) {
case 2:
    A1 = A;
    B1 = A + k;
    C1 = A + j;
    break;
case 1:
    A1 = big_zero_array;
    B1 = A + k;
    C1 = A + j;
    break;
case 0:
    A1 = B1 = big_zero_array;
    C1 = A + j
    break;
}

for (int i = 0; i < N; i += inc) {
    v = A1[i] + B1[i] + C1[i];
    //....
}
开关(constVal){
案例2:
A1=A;
B1=A+k;
C1=A+j;
打破
案例1:
A1=大零阵列;
B1=A+k;
C1=A+j;
打破
案例0:
A1=B1=大零阵列;
C1=A+j
打破
}
对于(int i=0;i

不过,这需要额外的内存,在某些情况下可能会更慢。

您只需反转
开关的嵌套
for
(尽管您需要为每个
案例
编写
).您是否故意在每个案例后都没有
break
语句???是的,故意没有break语句。这只是为了说明问题。实际代码要复杂得多,这就是为什么我不需要多个副本。您可以