gpt4 book ai didi

c - 海湾合作委员会 4.4 : Avoid range check on switch/case statement in gcc?

转载 作者:太空狗 更新时间:2023-10-29 16:34:18 31 4
gpt4 key购买 nike

This is only an issue on GCC versions prior to 4.4, this was fixed in GCC 4.5.

是否可以告诉编译器 switch 中使用的变量适合提供的 case 语句?特别是如果它是一个小范围并且生成了一个跳转表。

extern int a;
main()
{
switch (a & 0x7) { // 0x7 == 111 values are 0-7
case 0: f0(); break;
case 1: f1(); break;
case 2: f2(); break;
case 3: f3(); break;
case 4: f4(); break;
case 5: f5(); break;
case 6: f6(); break;
case 7: f7(); break;
}
}

我尝试使用枚举对低位进行异或运算(作为示例),使用 gcc_unreachable() 无济于事。生成的代码始终检查变量是否在范围内,添加无意义的分支条件并移走跳表计算代码。

注意:这是在解码器的最内层循环中,性能非常重要。

看来我不是only one .

There is no way to tell gcc that the default branch is never taken, although it will omit the default branch if it can prove that the value is never out of range based on earlier conditional checks.

那么,您如何帮助 gcc 证明变量适合并且上面的示例中没有默认分支? (当然,不添加条件分支。)

更新

  1. 这是在带有 GCC 4.2(Xcode 的默认设置)的 OS X 10.6 Snow Leopard 上发生的。Linux 中的 GCC 4.4/4.3 没有发生(Nathon 和 Jens Gustedt 报告。)

    <
  2. 示例中的函数是为了提高可读性,认为它们是内联的或只是语句。在 x86 上进行函数调用非常昂贵。

    此外,如注释中所述,该示例属于数据(大数据)循环内。

    gcc 4.2/OS X 生成的代码是:

    [...]
    andl $7, %eax
    cmpl $7, %eax
    ja L11
    mov %eax, %eax
    leaq L20(%rip), %rdx
    movslq (%rdx,%rax,4),%rax
    addq %rdx, %rax
    jmp *%rax
    .align 2,0x90
    L20:
    .long L12-L20
    .long L13-L20
    .long L14-L20
    .long L15-L20
    .long L16-L20
    .long L17-L20
    .long L18-L20
    .long L19-L20
    L19:
    [...]

    问题出在cmp $7, %eax; ja L11;

  3. 好的,我将采用丑陋的解决方案,并使用不带开关的不同版本并使用 goto 和 gcc 的 &&label 扩展为 4.4 以下的 gcc 版本添加一个特殊情况。

    static void *jtb[] = { &&c_1, &&c_2, &&c_3, &&c_4, &&c_5, &&c_6, &&c_7, &&c_8 };
    [...]
    goto *jtb[a & 0x7];
    [...]
    while(0) {
    c_1:
    // something
    break;
    c_2:
    // something
    break;
    [...]
    }

    请注意,标签数组是静态的,因此不会在每次调用时都对其进行计算。

最佳答案

或许您可以使用函数指针数组来代替开关?

#include <stdio.h>

typedef void (*func)(void);

static void f0(void) { printf("%s\n", __FUNCTION__); }
static void f1(void) { printf("%s\n", __FUNCTION__); }
static void f2(void) { printf("%s\n", __FUNCTION__); }
static void f3(void) { printf("%s\n", __FUNCTION__); }
static void f4(void) { printf("%s\n", __FUNCTION__); }
static void f5(void) { printf("%s\n", __FUNCTION__); }
static void f6(void) { printf("%s\n", __FUNCTION__); }
static void f7(void) { printf("%s\n", __FUNCTION__); }

int main(void)
{
const func f[8] = { f0, f1, f2, f3, f4, f5, f6, f7 };
int i;

for (i = 0; i < 8; ++i)
{
f[i]();
}
return 0;
}

关于c - 海湾合作委员会 4.4 : Avoid range check on switch/case statement in gcc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3250178/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com