I have a function called fc which executes a jump statement after doing some operations.
#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;
}
If I compile it using -O0, the .ll file is ok, like this:
clang test.c -S -emit-llvm -O0
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
}
But if I compile it using -O2, the .ll file is weird, like below:
clang test.c -S -emit-llvm -O2
; 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
}
The label 6 is an infinite loop, even if the parameter t->b1 of fc is modified in another thread, the loop will go on. I tried it with llvm11.1.0 and 13.0.1, the result is the same.
So my question is, is there some command line parameter that can solve this problem? Or other solutions.
In fact, I'm using llvm to implement a graphical programming language without the volatile keyword. After translating the language to IR, I had to set volatile for some LoadInst and StoreInst.
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);
}
}
This code does the trick, but is a bit ugly.