/
codegen.c
153 lines (139 loc) · 3.14 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
#include "chibi.h"
static int labelseq = 1;
// Pushes the given node's address to the stack.
static void gen_addr(Node *node) {
if (node->kind == ND_VAR) {
printf(" lea rax, [rbp-%d]\n", node->var->offset);
printf(" push rax\n");
return;
}
error("not an lvalue");
}
static void load(void) {
printf(" pop rax\n");
printf(" mov rax, [rax]\n");
printf(" push rax\n");
}
static void store(void) {
printf(" pop rdi\n");
printf(" pop rax\n");
printf(" mov [rax], rdi\n");
printf(" push rdi\n");
}
// Generate code for a given node.
static void gen(Node *node) {
switch (node->kind) {
case ND_NUM:
printf(" push %ld\n", node->val);
return;
case ND_EXPR_STMT:
gen(node->lhs);
printf(" add rsp, 8\n");
return;
case ND_VAR:
gen_addr(node);
load();
return;
case ND_ASSIGN:
gen_addr(node->lhs);
gen(node->rhs);
store();
return;
case ND_IF: {
int seq = labelseq++;
if (node->els) {
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.else.%d\n", seq);
gen(node->then);
printf(" jmp .L.end.%d\n", seq);
printf(".L.else.%d:\n", seq);
gen(node->els);
printf(".L.end.%d:\n", seq);
} else {
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.end.%d\n", seq);
gen(node->then);
printf(".L.end.%d:\n", seq);
}
return;
}
case ND_WHILE: {
int seq = labelseq++;
printf(".L.begin.%d:\n", seq);
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.end.%d\n", seq);
gen(node->then);
printf(" jmp .L.begin.%d\n", seq);
printf(".L.end.%d:\n", seq);
return;
}
case ND_RETURN:
gen(node->lhs);
printf(" pop rax\n");
printf(" jmp .L.return\n");
return;
}
gen(node->lhs);
gen(node->rhs);
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_EQ:
printf(" cmp rax, rdi\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
break;
case ND_NE:
printf(" cmp rax, rdi\n");
printf(" setne al\n");
printf(" movzb rax, al\n");
break;
case ND_LT:
printf(" cmp rax, rdi\n");
printf(" setl al\n");
printf(" movzb rax, al\n");
break;
case ND_LE:
printf(" cmp rax, rdi\n");
printf(" setle al\n");
printf(" movzb rax, al\n");
break;
}
printf(" push rax\n");
}
void codegen(Function *prog) {
printf(".intel_syntax noprefix\n");
printf(".global main\n");
printf("main:\n");
// Prologue
printf(" push rbp\n");
printf(" mov rbp, rsp\n");
printf(" sub rsp, %d\n", prog->stack_size);
// Emit code
for (Node *node = prog->node; node; node = node->next)
gen(node);
// Epilogue
printf(".L.return:\n");
printf(" mov rsp, rbp\n");
printf(" pop rbp\n");
printf(" ret\n");
}