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
相关产品推荐
相关产品推荐

