LLVM架构
clang test.cpp -o test
的执行步骤:
前端语法分析
Bash clang -Xclang -ast-dump -fsyntax-only test.cpp
输出test.cpp经过编译器前端的预处理、语法分析、语义分析之后生成的抽象语法树(AST),最后几行显示了经过分析后的AST
C++ ` - FunctionDecl 0x55d7ecff3d90 < test . cpp : 1 : 1 , line : 4 : 1 > line : 1 : 5 main ' int () '
` - CompoundStmt 0x55d7ecff3ed0 < line : 2 : 1 , line : 4 : 1 >
` - ReturnStmt 0x55d7ecff3ec0 < line : 3 : 5 , col : 12 >
` - IntegerLiteral 0x55d7ecff3ea0 < col : 12 > ' int ' 0
前端生成中间代码
第二步骤时将内存中的AST生成LLVM IR中间代码。
Bash clang++ -S -emit-llvm test.cpp
生成一个test.ll文件
Bash ; ModuleID = 'test.cpp'
source_filename = "test.cpp"
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-unknown-linux-gnu"
; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
define dso_local noundef i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0 , i32* %1, align 4
ret i32 0
}
attributes #0 = { mustprogress noinline norecurse nounwind optnone 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" }
!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 13.0.0 (https://github.com/apple/llvm-project.git f0fb631dd1a3a2988b23ba5057cd9106713cd0b4)" }
其中的define i32 @main()
即源代码转化为LLVM IR的核心部分
LLVM后端优化IR
使用llvm中的opt进行O3优化
Bash opt test.ll -S -O3
# 或者
clang++ -S -emit-llvm -O3 test.cpp
Bash ; ModuleID = 'test.cpp'
source_filename = "test.cpp"
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-unknown-linux-gnu"
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn uwtable
define dso_local noundef i32 @main() local_unnamed_addr #0 {
ret i32 0
}
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn uwtable "frame-pointer"="none" "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" }
!llvm.module.flags = !{ !0, !1, !2, !3}
!llvm.ident = !{ !4}
!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 = !{ !"clang version 13.0.0 (https://github.com/apple/llvm-project.git f0fb631dd1a3a2988b23ba5057cd9106713cd0b4)" }
LLVM后端生成汇编代码
使用llc组件llc test.ll
,生成test.s
S .text
.file "test.cpp"
.globl main # -- Begin function main
.p2align 4 , 0x90
.type main , @ function
main : # @main
.cfi_startproc
# %bb.0:
xorl %eax, % eax
retq
.Lfunc_end0 :
.size main , .Lfunc_end0 - main
.cfi_endproc
# -- End function
.ident "clang version 13.0.0 (https://github.com/apple/llvm-project.git f0fb631dd1a3a2988b23ba5057cd9106713cd0b4)"
.section ".note.GNU-stack" , "" , @ progbits
然后就是操作系统自带的汇编器、连接器。最终生成可执行程序(.s ==OS Assembler -> .o ==OS Linker -> executable)