1 Program generation and running experiments
1.1 Preprocessing
- The do-while-zero macro is used to press multiple statements in a macro;
1.2 Compilation
In this unit, you will learn several important steps about C program compilation and several intermediate representations of C programs, including Abstract Syntax Tree (AST) and LLVM Intermediate Representation (IR), and finally have a look at compilation optimization. Initial understanding.
LLVM AST
slightly
LLVM AND
LLVM IR reading materials:
loop in LLVM IR
int main() {
int i = 0; // %2
int sum = 0; // %3
for (i = 0; i < 10; i++) {
sum += i;
}
while (sum > 0) {
sum --;
}
return 0;
}
Please note that the following IR document is not complete, only the key parts are listed.
define dso_local i32 @main() #0 {
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, ptr %2, align 4
store i32 0, ptr %3, align 4
store i32 0, ptr %2, align 4 ; 同名变量 i,因此复用 %2
br label %4
4: ; preds = %11, %0
%5 = load i32, ptr %2, align 4
%6 = icmp slt i32 %5, 10
br i1 %6, label %7, label %14
; i < 10
7: ; preds = %4
%8 = load i32, ptr %2, align 4
%9 = load i32, ptr %3, align 4
%10 = add nsw i32 %9, %8
store i32 %10, ptr %3, align 4
br label %11
; sum += i
11: ; preds = %7
%12 = load i32, ptr %2, align 4
%13 = add nsw i32 %12, 1
store i32 %13, ptr %2, align 4
br label %4, !llvm.loop !6
; i++
14: ; preds = %4
br label %15
15: ; preds = %18, %14
%16 = load i32, ptr %3, align 4
%17 = icmp sgt i32 %16, 0
br i1 %17, label %18, label %21
18: ; preds = %15
%19 = load i32, ptr %3, align 4
%20 = add nsw i32 %19, -1
store i32 %20, ptr %3, align 4
br label %15, !llvm.loop !8
21: ; preds = %15
ret i32 0
}
static and global variables in LLVM IR
#include <stdio.h>
void sayHello() {
printf("Hello, world!\n");
}
void incrementAndPrint() {
static int count = 0;
count ++;
printf("Count: %d\n", count);
}
int main() {
sayHello();
incrementAndPrint();
incrementAndPrint();
incrementAndPrint();
return 0;
}
@.str = private unnamed_addr constant [15 x i8] c"Hello, world!\0A\00", align 1
@incrementAndPrint.count = internal global i32 0, align 4
@.str.1 = private unnamed_addr constant [11 x i8] c"Count: %d\0A\00", align 1
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local void @sayHello() #0 {
%1 = call i32 (ptr, ...) @printf(ptr noundef @.str)
ret void
}
declare i32 @printf(ptr noundef, ...) #1
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local void @incrementAndPrint() #0 {
%1 = load i32, ptr @incrementAndPrint.count, align 4
%2 = add nsw i32 %1, 1
store i32 %2, ptr @incrementAndPrint.count, align 4
%3 = load i32, ptr @incrementAndPrint.count, align 4
%4 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %3)
ret void
}
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, ptr %1, align 4
call void @sayHello()
call void @incrementAndPrint()
call void @incrementAndPrint()
call void @incrementAndPrint()
ret i32 0
}
attributes #0 = {
noinline nounwind optnone sspstrong uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = {
"frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{
!0, !1, !2, !3, !4}
!llvm.ident = !{
!5}
!0 = !{
i32 1, !"wchar_size", i32 4}
!1 = !{
i32 7, !"PIC Level", i32 2}
!2 = !{
i32 7, !"PIE Level", i32 2}
!3 = !{
i32 7, !"uwtable", i32 2}
!4 = !{
i32 7, !"frame-pointer", i32 2}
!5 = !{
!"clang version 15.0.7"}
how to merge 2 funtions?
- Demand attention
inline
Sum__attribute__((always_inline))
Differentiation
#include <stdio.h>
__attribute__((always_inline)) int findMax(int a, int b) {
return (a > b) ? a : b;
}
int main() {
int num1 = 10; // %4
int num2 = 20; // %5
int max_num = findMax(num1, num2);
printf("The maximum between %d and %d is %d\n", num1, num2, max_num);
return 0;
}
This section of IR involves the phi instruction
%4 = phi i32 [ 1, %1 ], [ %8, %5 ] ; 如果是从块 %1 来的,那么值就是 1,如果是从块 %5 来的,那么值就是 %8 的值
The IR is as follows:
@.str = private unnamed_addr constant [37 x i8] c"The maximum between %d and %d is %d\0A\00", align 1
; Function Attrs: alwaysinline nounwind sspstrong uwtable
define dso_local i32 @findMax(i32 noundef %0, i32 noundef %1) #0 {
%3 = alloca i32, align 4 ; a
%4 = alloca i32, align 4 ; b
store i32 %0