-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcodegen.c
237 lines (208 loc) · 5.56 KB
/
codegen.c
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "0cc.h"
// スタックのトップに変数のアドレスを置く
void gen_lval(Node *node) {
if (node->kind != ND_LVAR)
error("代入の左辺値が変数ではありません");
printf(" mov rax, rbp\n");
printf(" sub rax, %d\n", node->offset);
printf(" push rax\n");
}
void gen_if(Node *node) {
if (node->kind != ND_IFELSE) {
printf(" je .Lend%d\n", node->val);
gen(node);
return;
}
printf(" je .Lelse%d\n", node->val);
gen(node->lhs);
printf(" jmp .Lend%d\n", node->val);
printf(".Lelse%d:\n", node->val);
gen(node->rhs);
}
void gen_for_cond(Node *node) {
if (node->kind != ND_FOR_COND)
error("不正なASTです\n");
if (node->lhs) {
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .Lend%d\n", node->val);
}
// ND_FOR_UPDT_STMT の処理を委譲する
gen_for_updt_stmt(node->rhs);
}
void gen_for_updt_stmt(Node *node) {
if (node->kind != ND_FOR_UPDT_STMT)
error("不正なASTです\n");
gen(node->rhs);
if (node->lhs)
gen(node->lhs);
printf(" jmp .Lbegin%d\n", node->val);
}
void gen_func_call(Node *node) {
int i = 0;
for (; node->args[i] && i < 6; i++) {
gen(node->args[i]);
}
i--;
while (i >= 0) printf(" pop %s\n", ARG_RGST[i--]);
/*
x86-64のABIのため
RSPが16の倍数になるように調整
*/
// 現在のRSPを保存
printf(" mov rax, rsp\n");
// 16バイトアラインメントをチェック
printf(" and rax, 15\n");
printf(" jz .Lcall%d\n", node->val);
// アラインメントが必要な場合
printf(" sub rsp, 8\n");
printf(" call %s\n", node->name);
printf(" add rsp, 8\n");
printf(" jmp .Lend%d\n", node->val);
// アラインメントが不要な場合
printf(".Lcall%d:\n", node->val);
printf(" call %s\n", node->name);
printf(".Lend%d:\n", node->val);
printf(" push rax\n");
}
void gen(Node *node) {
switch (node->kind) {
case ND_NUM:
printf(" push %d\n", node->val);
return;
case ND_LVAR:
gen_lval(node);
// ここでスタックトップのアドレスのメモリに保存されている値を取り出す
printf(" pop rax\n");
printf(" mov rax, [rax]\n");
printf(" push rax\n");
return;
case ND_ASSIGN:
gen_lval(node->lhs);
gen(node->rhs);
printf(" pop rdi\n");
printf(" pop rax\n");
printf(" mov [rax], rdi\n");
printf(" push rdi\n");
return;
case ND_RETURN:
gen(node->lhs);
printf(" pop rax\n");
printf(" mov rsp, rbp\n");
printf(" pop rbp\n");
printf(" ret\n");
return;
case ND_IF:
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
gen_if(node->rhs);
printf(".Lend%d:\n", node->val);
return;
case ND_WHILE:
printf(".Lbegin%d:\n", node->val);
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .Lend%d\n", node->val);
gen(node->rhs);
printf(" jmp .Lbegin%d\n", node->val);
printf(".Lend%d:\n", node->val);
return;
case ND_FOR_INIT:
if (node->lhs)
gen(node->lhs);
printf(".Lbegin%d:\n", node->val);
// ND_FOR_COND の処理を委譲する
gen_for_cond(node->rhs);
printf(".Lend%d:\n", node->val);
return;
case ND_BLOCK:
int i = 0;
// stmts を取り出す
while (node->stmts[i]) {
gen(node->stmts[i++]);
printf(" pop rax\n");
}
return;
case ND_FUNC_CALL:
gen_func_call(node);
return;
}
gen(node->lhs);
gen(node->rhs);
// 奥に入っているのが第2項: rdi
// 手間に入っているのが第1項: rax
printf(" pop rdi\n");
printf(" pop rax\n");
switch (node->kind) {
case ND_ADD:
printf(" add rax, rdi\n");
break;
case ND_SUB:
printf(" sub rax, rdi\n");
break;
case ND_MUL:
printf(" imul rax, rdi\n");
break;
case ND_DIV:
printf(" cqo\n");
printf(" idiv rdi\n");
break;
case ND_MOD:
printf(" cqo\n");
printf(" idiv rdi\n");
printf(" mov rax, rdx\n");
break;
case ND_EQU:
printf(" cmp rax, rdi\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
break;
case ND_NEQ:
printf(" cmp rax, rdi\n");
printf(" setne al\n");
printf(" movzb rax, al\n");
break;
case ND_LES:
printf(" cmp rax, rdi\n");
printf(" setl al\n");
printf(" movzb rax, al\n");
break;
case ND_LEQ:
printf(" cmp rax, rdi\n");
printf(" setle al\n");
printf(" movzb rax, al\n");
break;
}
printf(" push rax\n");
}
void gen_func(Node *node) {
if (node->kind != ND_FUNC)
error("ND_FUNC expected but found %d\n", node->kind);
printf("%s:\n", node->name);
// プロローグ
printf(" push rbp\n");
printf(" mov rbp, rsp\n");
printf(" sub rsp, %d\n", node->offset);
// 関数の引数のレジスタの値を変数に保存
int arg_idx = 0;
Node *arg;
while (arg = node->args[arg_idx]) {
gen_lval(arg);
printf(" pop rax\n");
printf(" mov [rax], %s\n", ARG_RGST[arg_idx++]);
}
Node *stmt;
for (int i = 0; stmt = node->stmts[i]; i++) {
gen(stmt);
printf(" pop rax\n");
}
// エピローグ
// 変数で確保しておいたRSPをRBPと同じ場所に戻す
printf(" mov rsp, rbp\n");
// popでRSPがリターンアドレスを指し、RBPを関数呼び出し前のRBPに戻す
printf(" pop rbp\n");
printf(" ret\n");
}