I'm just getting started with LLVM. Consider the following programs.
hello1.c
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
}
hello2.c
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
These generate the following LLVM IR strings
$ clang -S -emit-llvm -o hello1.ll hello1.c
$ clang -S -emit-llvm -o hello2.ll hello2.c
$ clang --version
Debian clang version 11.0.1-2
hello1.ll
; ModuleID = 'res/c/hello.c'
source_filename = "res/c/hello.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
@.str = private unnamed_addr constant [15 x i8] c"Hello, world!\0A\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i64 0, i64 0))
ret i32 0
}
declare dso_local i32 @printf(i8*, ...) #1
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"Debian clang version 11.0.1-2"}
hello2.ll
; ....
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i64 0, i64 0))
ret i32 0
}
; ....
As you can see, the addition of the return 0
appears to generate the allocation of a new stack temporary %1
with value 0. It doesn't seem that this value is used anywhere. Even if I change the return stmt to, e.g., return -1
, there is still the allocation and zeroing of the temporary %1
, and the constant literal only appears in the return instruction ret i32 -1
.
I know that this will be inconsequential due to optimizations (e.g., live variable analysis). Is this an idiosyncrasy of the clang handling of return statements or is there a deeper reason for this?