You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LLVM-O2优化将带goto的代码转为无限循环,求解决方案

问题背景

我有一个名为fc的函数,执行若干操作后会执行跳转语句,对应的C代码如下:

#include <stdbool.h>

struct Test
{
    int var1;
    int var2;
    bool b1;
};

void fc(struct Test *t)
{
label:
    t->var2 = 123;
    if (t->b1)
        t->var1 += t->var2;
    if (t->b1)
        goto label;
    return;
}

使用-O0编译生成的LLVM IR文件符合预期,编译命令为clang test.c -S -emit-llvm -O0,对应的IR代码如下:

define dso_local void @fc(%struct.Test* %0) #0 {
  %2 = alloca %struct.Test*, align 8
  store %struct.Test* %0, %struct.Test** %2, align 8
  br label %3

3:                                                ; preds = %23, %1
  %4 = load %struct.Test*, %struct.Test** %2, align 8
  %5 = getelementptr inbounds %struct.Test, %struct.Test* %4, i32 0, i32 1
  store i32 123, i32* %5, align 4
  %6 = load %struct.Test*, %struct.Test** %2, align 8
  %7 = getelementptr inbounds %struct.Test, %struct.Test* %6, i32 0, i32 2
  %8 = load i8, i8* %7, align 4
  %9 = trunc i8 %8 to i1
  br i1 %9, label %10, label %18

10:                                               ; preds = %3
  %11 = load %struct.Test*, %struct.Test** %2, align 8
  %12 = getelementptr inbounds %struct.Test, %struct.Test* %11, i32 0, i32 1
  %13 = load i32, i32* %12, align 4
  %14 = load %struct.Test*, %struct.Test** %2, align 8
  %15 = getelementptr inbounds %struct.Test, %struct.Test* %14, i32 0, i32 0
  %16 = load i32, i32* %15, align 4
  %17 = add nsw i32 %16, %13
  store i32 %17, i32* %15, align 4
  br label %18

18:                                               ; preds = %10, %3
  %19 = load %struct.Test*, %struct.Test** %2, align 8
  %20 = getelementptr inbounds %struct.Test, %struct.Test* %19, i32 0, i32 2
  %21 = load i8, i8* %20, align 4
  %22 = trunc i8 %21 to i1
  br i1 %22, label %23, label %24

23:                                               ; preds = %18
  br label %3

24:                                               ; preds = %18
  ret void
}

但使用-O2编译时,生成的IR出现异常,编译命令为clang test.c -S -emit-llvm -O2,对应的IR代码如下:

; Function Attrs: nofree norecurse nounwind uwtable
define dso_local void @fc(%struct.Test* nocapture %0) local_unnamed_addr #0 {
  %2 = getelementptr inbounds %struct.Test, %struct.Test* %0, i64 0, i32 1
  store i32 123, i32* %2, align 4, !tbaa !3
  %3 = getelementptr inbounds %struct.Test, %struct.Test* %0, i64 0, i32 2
  %4 = load i8, i8* %3, align 4, !tbaa !9, !range !10
  %5 = icmp eq i8 %4, 0
  br i1 %5, label %7, label %6

6:                                                ; preds = %1, %6
  br label %6

7:                                                ; preds = %1
  ret void
}

其中label 6是一个无限循环,即便其他线程修改fc的参数t->b1,该循环也会持续执行。我在LLVM 11.1.0和13.0.1版本中均测试过,结果一致。

当前解决方案

我正在基于LLVM实现一款无volatile关键字的图形化编程语言,目前通过将IR中的部分LoadInst和StoreInst设置为volatile来解决此问题,对应的代码如下:

Function *function = kit_->currFunction();
size_t old_block_size = function->getBasicBlockList().size();
IteratorVisitor::visit(mem);
if (!containsJump(mem))
    return;
size_t index = 0;
for (Function::iterator block = function->begin(); block != function->end(); ++block) {
    if (++index < old_block_size)
        continue;
    for (BasicBlock::iterator inst = block->begin(); inst != block->end(); ++inst) {
        if (llvm::isa<llvm::StoreInst>(inst))
            llvm::dyn_cast<llvm::StoreInst>(inst)->setVolatile(true);
        else if (llvm::isa<llvm::LoadInst>(inst))
            llvm::dyn_cast<llvm::LoadInst>(inst)->setVolatile(true);
    }
}

该方法可以解决问题,但实现方式不够优雅。

提问

是否有可用的命令行参数或其他更优的解决方案?


内容的提问来源于stack exchange,提问作者Desmondo Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:24:56