GCC 的计算 goto 的 ISO C 替换

ktb*_*ktb 5 c assembly gcc micro-optimization

背景:

在解释器循环(或其他有限状态机)中,有几种方法可以分派操作(或基于下一个输入的跳转状态)。C 中显而易见的方法是在循环中使用 switch 语句。但是,在循环内使用 switch 存在性能问题。在最坏的情况下,开关可以被编码为一个分支序列,如果操作编码不连续(或者编译器无法推断它是连续的),就会发生这种情况。即使在编译器生成跳转表的乐观情况下,仍然有多余的跳转回调度程序(我还没有看到编译器在看到循环中的开关时内联调度)。此外,调度程序中通常有一个冗余的边界检查。

GCC 团队通过引入 Computed Goto 解决了这个问题。这是一种语言扩展,允许引用标签,稍后可以跳转到goto标签指针上使用。这生成了理想的汇编代码:一个操作码索引的跳转表,在每次操作后都带有内联调度。

题:

有没有办法使用 ISO C 生成类似的汇编代码?

笔记:

我能做到的最接近的方法是将每个操作编写为一个函数,将函数指针放在一个表中,并利用尾调用优化来生成跳转而不是调用。这个问题很明显:它依赖于可能存在也可能不存在的优化。如果没有优化,生成的代码将消耗堆栈并最终使应用程序崩溃。

我试图生成的理想汇编代码(GAS .intel_syntax,类似于 NASM 语法)

.intel_syntax  noprefix

.section .rodata
optable:
  .quad nop
  .quad add
  # more ops here

.section .text
## interpreter loop entry here
nop:
    call  nextinput          # return value = table index in rax
    jmp   [optable + rax]

add:
    # add stuff here
    call  nextinput
    jmp   [optable + rax]
Run Code Online (Sandbox Code Playgroud)