1 程序生成与运行实验
1.1 预处理
- do-while-zero 宏用于在宏里压多条语句;
1.2 编译
在本单元中,你将会学习到有关C程序编译的几个重要步骤和几种C程序的中间表示形式,包括抽象语法树(AST)和LLVM中间表示(IR),最后对编译优化有个初步了解。
LLVM AST
略
LLVM IR
LLVM IR阅读材料:
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;
}
注意下面的IR非完整文件,只列了关键部分
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?
- 需要注意
inline
和__attribute__((always_inline))
的区别
#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;
}
本节IR涉及到 phi 指令
%4 = phi i32 [ 1, %1 ], [ %8, %5 ] ; 如果是从块 %1 来的,那么值就是 1,如果是从块 %5 来的,那么值就是 %8 的值
IR如下:
@.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