MimiC编译器源码阅读

MimiC is a compiler of C subset (extended SysY language) by USTB NSCSCC team.

#使用说明

#源语言定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
comp_unit       ::= {decl | type_def | func_def};
decl ::= var_decl | func_decl;
type_def ::= struct_def | enum_def | type_alias;
func_def ::= func_header block;

var_decl ::= type var_def {"," var_def} ";";
var_def ::= ID_VAL {"[" expr "]"} ["=" init_val];
init_val ::= expr | "{" [init_val {"," init_val}] "}";

func_decl ::= func_header ";";
func_header ::= type ID_VAL "(" [func_params] ")";
func_params ::= func_param {"," func_param};
func_param ::= type ID_VAL ["[" [expr] "]" {"[" expr "]"}];

struct_def ::= "struct" ID_VAL "{" {struct_elem} "}" ";";
enum_def ::= "enum" [ID_VAL] "{" enum_elems "}" ";";
type_alias ::= "typedef" type ID_VAL ";";
struct_elem ::= type struct_elem_def {"," struct_elem_def} ";";
struct_elem_def ::= ID_VAL {"[" expr "]"};
enum_elems ::= ID_VAL ["=" expr] ["," enum_elems] [","];

block ::= "{" {block_item} "}";
block_item ::= decl | type_def | stmt;

stmt ::= bare | block | if_else | while | control;
bare ::= expr ";";
if_else ::= "if" "(" expr ")" stmt ["else" stmt];
while ::= "while" "(" expr ")" stmt;
control ::= ("break" | "continue" | ("return" [expr])) ";";

expr ::= cast {bin_op cast};
cast ::= {"(" type ")"} unary;
unary ::= {unary_op} factor | "sizeof" (factor | "(" type ")");
factor ::= value | index | func_call | access | "(" expr ")";

bin_op ::= "+" | "-" | "*" | "/" | "%" | "&"
| "|" | "^" | "&&" | "||" | "<<" | ">>"
| "==" | "!=" | "<" | "<=" | ">" | ">="
| "=" | "+=" | "-=" | "*=" | "/=" | "%="
| "&=" | "|=" | "^=" | "<<=" | ">>=";
unary_op ::= "+" | "-" | "!" | "~" | "*" | "&";

value ::= INT_VAL | CHAR_VAL | STR_VAL | ID_VAL;
index ::= expr "[" expr "]";
func_call ::= expr "(" [expr {"," expr}] ")";
access ::= factor ("." | "->") ID_VAL;

type ::= prim_type | struct_type | enum_type | const | pointer
| user_type;
prim_type ::= "void" | ["unsigned"] "int" | "char";
struct_type ::= "struct" ID_VAL;
enum_type ::= "enum" ID_VAL;
const ::= "const" type;
pointer ::= type "*" {"*"};
user_type ::= ID_VAL;

#目标语言

  • C
  • riscv32
  • aarch32

#构建&使用

1
2
3
mkdir build && cd build
cmake ..
make -j32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
./mmcc -h
Usage: mmcc <INPUT> [OPTIONS...]

Arguments:
input input source file

Options:
-h, --help show this message
-v, --version show version info
-S, --asm dump assembly
-O2, --opt-2 enable level-2 optimization
-o, --output <ARG> output file, default to stdout
-V, --verbose use verbose output
-Werror, --warn-error treat warnings as errors
-Wall, --warn-all enable all warnings
-da, --dump-ast dump AST to output
-di, --dump-ir dump IR to output
-ps, --pass-stage <ARG> optimize until specific stage
-ta, --target-arch <ARG> specify target architecture

#实现

#模块划分

  • back/
  • define/
  • driver
  • front
  • mid
  • opt
  • utils

#类设计

mimic-uml.excalidraw.svg

#Pass注册

利用static变量最先执行的特性,由PassManager提供一个注册函数,用于保存当前pass。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class PassManager {
public:
// register a new pass
template <typename T>
static PassInfo &RegisterPass(std::string_view name) {
static_assert(!std::is_base_of_v<HelperPass, T>,
"helper pass is unregisterable");
auto &passes = GetPasses();
assert(!passes.count(name) && "pass has already been registered");
return passes.insert({name, PassInfo(std::make_unique<T>(), name)})
.first->second;
}

private:
// get pass info list
static PassInfoMap &GetPasses();
};

// In passman.cpp
PassManager::PassInfoMap &PassManager::GetPasses() {
static PassInfoMap passes;
return passes;
}

// register a pass
#define REGISTER_PASS(cls, name) \
static PassInfo &pass_##name = PassManager::RegisterPass<cls>(#name)
1
2
3
4
// register current pass
REGISTER_PASS(PhiSimplifyPass, phi_simp)
.set_min_opt_level(1)
.set_stages(PassStage::Promote);