对于这样的 C 程序:
struct test_struct1 {
int *a;
int b;
};
int main(int argc, char *argv[]) {
int a = 1;
struct test_struct1 t1 = {&a, 0};
return 0;
}
生成的IR代码如下:
; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32"
%struct.test_struct1 = type { ptr, i32 } *** ①***
; Function Attrs: noinline nounwind optnone
define hidden i32 @__main_argc_argv(i32 noundef %0, ptr noundef %1) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca ptr, align 4
%6 = alloca i32, align 4
%7 = alloca %struct.test_struct1, align 4
store i32 0, ptr %3, align 4
store i32 %0, ptr %4, align 4
store ptr %1, ptr %5, align 4
store i32 1, ptr %6, align 4 ***②***
%8 = getelementptr inbounds %struct.test_struct1, ptr %7, i32 0, i32 0
store ptr %6, ptr %8, align 4
%9 = getelementptr inbounds %struct.test_struct1, ptr %7, i32 0, i32 1
store i32 0, ptr %9, align 4
ret i32 0
}
attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+mutable-globals,+sign-ext" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 16.0.6"}
在上面生成的IR代码中,①是生成的结构体类型,②是生成访问指令(加载/存储)。我想知道 LLVM 源代码中的哪一部分负责①和②。
我希望熟悉LLVM源代码的人可以告诉我答案或者一些如何解决的想法,比如去哪部分代码。非常感谢您的帮助。
学习Clang+LLVM设计的起点是 各个组件的文档页面:
对于使用 C 语言的代码进行解析和代码生成的任务
struct
,
“Clang”CFG 内部手册
将是开始的地方,特别是
词法分析器和预处理器库,
解析器库
(虽然很简短),并且
AST 库。
词法分析器和解析器的工作是将 C/C++ 源代码转换为
抽象语法树(AST);这是编译器“前端”。
代码生成器或“后端”负责生成 LLVM IR 来自 AST。不幸的是,内部文档 CodeGen 库 只是一个带有几个链接的句子。而且,更一般地说, 这些“内部”文件往往提供概念性概述,而不是 比代码详细信息。
幸运的是,这两个组件都有 doxygen 生成的文档, 详细描述了命名空间、类和函数,并具有 直接指向源代码:
对于这两者,索引页本身并没有太多信息, 但顶部的菜单有指向名称空间、类等的链接,可以 被浏览。与任何大型软件一样,需要一段时间才能完成 习惯命名约定,但是一旦习惯了,就可以在 类列表通常是查找某些内容的最快方法。 (对于铿锵来说, 我的首选书签是
clang
命名空间
页。)
与解析
struct
相关的内容包括:
clang::Lexer
clang::Parser
clang::Sema
,
它将 Parser
创建的原始 AST 转换为“真正的”AST
供后续阶段使用。
clang::RecordDecl
,
代表 C struct
的 AST 节点。
更具体地
struct
:
clang::Parser::ParseStructDeclaration
解析 struct
。请注意,该链接是 github 存储库,而不是
比 doxygen 文档,因为后者省略了私有方法
而且这个方法恰好是私有的。在某个时刻,没有
代替直接搜索代码。
clang::Sema::ActOnTag
我认为,这是构建 RecordDecl
s 的主要函数。
与生成 LLVM IR 以操作
struct
相关的内容包括:
clang::CodeGen
一般命名空间。
clang::CodeGen::CGRecordLayout
,
它涉及将 Clang 记录类型转换为 LLVM 记录类型。
clang::CodeGen::CodeGenFunction
,
它发出用于读取和写入 LLVM 记录的 LLVM IR 指令
类型等。