记一个有趣的编译优化选项 `-enable-dfa-jump-thread`

"Hello World, Hello Blog"

Posted by nothin on September 22, 2025

记一个有趣的编译优化选项

前言是师姐在测试coremark时,发现gcc和icx的性能比llvm的性能要好。查看汇编代码发现,gcc和icx能将coremark中的一个状态机代码优化为使用goto串联起来状态转换过程,从而不需要使用跳转表来执行跳转流程。然后交给我任务来调研llvm中是否有相关的优化。

coremark源代码

coremark中的代码位于https://github.com/eembc/coremark/blob/main/core_state.c,一个经典的for套switch的状态机实现。

经过笔者调研,这是一种优化算法,但是可以直接手写为优化后的结果,类似的实现见:https://dev.to/lexplt/implementing-computed-gotos-in-c-193p

该网站的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
std::vector<uint8_t> bytecode = readBytecode();
std::size_t pos = 0;
uint8_t inst = bytecode[pos];
{
    dispatch_op:
    switch (inst)
    {
        case DO_THIS:
            // ...
            inst = bytecode[pos];
            pos++;
            goto dispatch_op;
        case DO_THAT:
            // ...
            inst = bytecode[pos];
            pos++;
            goto dispatch_op;
        // ...
    }

终极优化后的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#define FETCH_INSTRUCTION()    \
    do {                       \
        inst = bytecode[pos];  \
        pos++;                 \
    } while (false)

#if USE_COMPUTED_GOTO
#  define DISPATCH_GOTO() goto opcodes[inst]
#  define TARGET(op) TARGET_##op
#else
#  define DISPATCH_GOTO() goto dispatch_op
#  define TARGET(op) case op:
#end

#define DISPATCH()        \
    FETCH_INSTRUCTION();  \
    DISPATCH_GOTO()

std::vector<uint8_t> bytecode = readBytecode();
std::size_t pos = 0;
uint8_t inst = bytecode[pos];
{
#if !USE_COMPUTED_GOTO
    dispatch_op:
    switch (inst)
#else
    const std::array opcodes = {
        &&TARGET_DO_THIS,
        &&TARGET_DO_THAT,
        &&TARGET_STOP_INTERPRETER
    };
#end
    {
        TARGET(DO_THIS)
        {
            // ...
            DISPATCH();
        }
        TARGET(DO_THAT)
        {
            // ...
            DISPATCH();
        }
        TARGET(STOP_INTERPRETER)
        {
            goto label_end;
        }
        // ...
    }
    label_end:
    do {} while (false);
}

这两个代码编译后的运行时间可以参见网站描述。

coremark代码相关优化结果示例代码

优化选项

经过笔者的调研,这个有趣的优化已经在llvm中实现了,选项为-enable-dfa-jump-thread,相应的commit链接为https://github.com/llvm/llvm-project/commit/02077da,不过默认关闭。

经过笔者测试,在O2基础上关闭和打开这个选项,会带来一定的性能提升。

  • 硬件设置 macOS m4处理器,16GB内存。
  • clang版本 ` clang version 14.0.6` 。

使用不同选项下,测试coremark的iteractions/sec为

-O2 -O2 -mllvm -enable-dfa-jump-thread
600000/12.211=49136.024 1100000/19.807=55,535.922

可见,能够获得比较明显的性能提升。

除此之外,笔者还学到一个新的语法,使用 && 运算符,获得一个label的地址,存储到一个数组中。然后goto 语句的目标地址使用索引来计算目标地址。见https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html