Reputation: 2245
I am trying to understand the clang compiler for C, and the intermediate code it produces.
I have a series of functions that compile, producing LLVM-IR and I don't understand why.
Here is the first:
int f(int x){
}
This produces the LLVM code
define i32 @f(i32 %x) nounwind uwtable readnone{
ret i32 undef
}
That is perfectly understandable I think. The function body is undefined!
Here is the next C function:
int f(int x){
if (x < 0)
{}
else
{}
}
When clang compiles this, it generates the exact same LLVM-IR. The compiler recognizes that the body is garbage, and returns undefined!!! The way LLVM knows this is garbage is its optimizer. Clang --> LLVM uses a "return value collector" convention -- when defining a function -- %1 is allocated as the "return value." All return statements update this value, and ultimately, there is one ret statement in LLVM at the end of the function body that essentially returns this value. LLVM sees that a variable is allocated and returned without being updated or initialized, and sets it to undefined.
Now for the kicker!!
int f(int x){
if (x<0)
{}
else
{
return 3;
}
}
Is converted to the following LLVM-IR.
define i32 @f(i32 %x) nounwind uwtable readnone {
ret i32 3
}
For some reason, the undefined code is pruned off. The C function should be undefined when (x<0)!! Can anyone explain why this code is pruned off?
Upvotes: 1
Views: 137
Reputation: 225132
3
is a perfectly reasonable return value for a function with undefined behaviour. Literally any return value would be allowed.
Upvotes: 5