1 Star 0 Fork 0

曹贤成/chibicc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
codegen.c 15.36 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
#include "chibi.h"
static char *argreg1[] = {"dil", "sil", "dl", "cl", "r8b", "r9b"};
static char *argreg2[] = {"di", "si", "dx", "cx", "r8w", "r9w"};
static char *argreg4[] = {"edi", "esi", "edx", "ecx", "r8d", "r9d"};
static char *argreg8[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"};
static int labelseq = 1;
static int brkseq;
static int contseq;
static char *funcname;
static void gen(Node *node);
// Pushes the given node's address to the stack.
static void gen_addr(Node *node) {
switch (node->kind) {
case ND_VAR: {
if (node->init)
gen(node->init);
Var *var = node->var;
if (var->is_local) {
printf(" lea rax, [rbp-%d]\n", var->offset);
printf(" push rax\n");
} else {
printf(" push offset %s\n", var->name);
}
return;
}
case ND_DEREF:
gen(node->lhs);
return;
case ND_MEMBER:
gen_addr(node->lhs);
printf(" pop rax\n");
printf(" add rax, %d\n", node->member->offset);
printf(" push rax\n");
return;
}
error_tok(node->tok, "not an lvalue");
}
static void gen_lval(Node *node) {
if (node->ty->kind == TY_ARRAY)
error_tok(node->tok, "not an lvalue");
gen_addr(node);
}
static void load(Type *ty) {
printf(" pop rax\n");
if (ty->size == 1) {
printf(" movsx rax, byte ptr [rax]\n");
} else if (ty->size == 2) {
printf(" movsx rax, word ptr [rax]\n");
} else if (ty->size == 4) {
printf(" movsxd rax, dword ptr [rax]\n");
} else {
assert(ty->size == 8);
printf(" mov rax, [rax]\n");
}
printf(" push rax\n");
}
static void store(Type *ty) {
printf(" pop rdi\n");
printf(" pop rax\n");
if (ty->kind == TY_BOOL) {
printf(" cmp rdi, 0\n");
printf(" setne dil\n");
printf(" movzb rdi, dil\n");
}
if (ty->size == 1) {
printf(" mov [rax], dil\n");
} else if (ty->size == 2) {
printf(" mov [rax], di\n");
} else if (ty->size == 4) {
printf(" mov [rax], edi\n");
} else {
assert(ty->size == 8);
printf(" mov [rax], rdi\n");
}
printf(" push rdi\n");
}
static void truncate(Type *ty) {
printf(" pop rax\n");
if (ty->kind == TY_BOOL) {
printf(" cmp rax, 0\n");
printf(" setne al\n");
}
if (ty->size == 1) {
printf(" movsx rax, al\n");
} else if (ty->size == 2) {
printf(" movsx rax, ax\n");
} else if (ty->size == 4) {
printf(" movsxd rax, eax\n");
}
printf(" push rax\n");
}
static void inc(Type *ty) {
printf(" pop rax\n");
printf(" add rax, %d\n", ty->base ? ty->base->size : 1);
printf(" push rax\n");
}
static void dec(Type *ty) {
printf(" pop rax\n");
printf(" sub rax, %d\n", ty->base ? ty->base->size : 1);
printf(" push rax\n");
}
static void gen_binary(Node *node) {
printf(" pop rdi\n");
printf(" pop rax\n");
switch (node->kind) {
case ND_ADD:
case ND_ADD_EQ:
printf(" add rax, rdi\n");
break;
case ND_PTR_ADD:
case ND_PTR_ADD_EQ:
printf(" imul rdi, %d\n", node->ty->base->size);
printf(" add rax, rdi\n");
break;
case ND_SUB:
case ND_SUB_EQ:
printf(" sub rax, rdi\n");
break;
case ND_PTR_SUB:
case ND_PTR_SUB_EQ:
printf(" imul rdi, %d\n", node->ty->base->size);
printf(" sub rax, rdi\n");
break;
case ND_PTR_DIFF:
printf(" sub rax, rdi\n");
printf(" cqo\n");
printf(" mov rdi, %d\n", node->lhs->ty->base->size);
printf(" idiv rdi\n");
break;
case ND_MUL:
case ND_MUL_EQ:
printf(" imul rax, rdi\n");
break;
case ND_DIV:
case ND_DIV_EQ:
printf(" cqo\n");
printf(" idiv rdi\n");
break;
case ND_BITAND:
case ND_BITAND_EQ:
printf(" and rax, rdi\n");
break;
case ND_BITOR:
case ND_BITOR_EQ:
printf(" or rax, rdi\n");
break;
case ND_BITXOR:
case ND_BITXOR_EQ:
printf(" xor rax, rdi\n");
break;
case ND_SHL:
case ND_SHL_EQ:
printf(" mov cl, dil\n");
printf(" shl rax, cl\n");
break;
case ND_SHR:
case ND_SHR_EQ:
printf(" mov cl, dil\n");
printf(" sar rax, cl\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");
}
// Generate code for a given node.
static void gen(Node *node) {
switch (node->kind) {
case ND_NULL:
return;
case ND_NUM:
if (node->val == (int)node->val) {
printf(" push %ld\n", node->val);
} else {
printf(" movabs rax, %ld\n", node->val);
printf(" push rax\n");
}
return;
case ND_EXPR_STMT:
gen(node->lhs);
printf(" add rsp, 8\n");
return;
case ND_VAR:
if (node->init)
gen(node->init);
gen_addr(node);
if (node->ty->kind != TY_ARRAY)
load(node->ty);
return;
case ND_MEMBER:
gen_addr(node);
if (node->ty->kind != TY_ARRAY)
load(node->ty);
return;
case ND_ASSIGN:
gen_lval(node->lhs);
gen(node->rhs);
store(node->ty);
return;
case ND_TERNARY: {
int seq = labelseq++;
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);
return;
}
case ND_PRE_INC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
inc(node->ty);
store(node->ty);
return;
case ND_PRE_DEC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
dec(node->ty);
store(node->ty);
return;
case ND_POST_INC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
inc(node->ty);
store(node->ty);
dec(node->ty);
return;
case ND_POST_DEC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
dec(node->ty);
store(node->ty);
inc(node->ty);
return;
case ND_ADD_EQ:
case ND_PTR_ADD_EQ:
case ND_SUB_EQ:
case ND_PTR_SUB_EQ:
case ND_MUL_EQ:
case ND_DIV_EQ:
case ND_SHL_EQ:
case ND_SHR_EQ:
case ND_BITAND_EQ:
case ND_BITOR_EQ:
case ND_BITXOR_EQ:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->lhs->ty);
gen(node->rhs);
gen_binary(node);
store(node->ty);
return;
case ND_COMMA:
gen(node->lhs);
gen(node->rhs);
return;
case ND_ADDR:
gen_addr(node->lhs);
return;
case ND_DEREF:
gen(node->lhs);
if (node->ty->kind != TY_ARRAY)
load(node->ty);
return;
case ND_NOT:
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" sete al\n");
printf(" movzb rax, al\n");
printf(" push rax\n");
return;
case ND_BITNOT:
gen(node->lhs);
printf(" pop rax\n");
printf(" not rax\n");
printf(" push rax\n");
return;
case ND_LOGAND: {
int seq = labelseq++;
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.false.%d\n", seq);
gen(node->rhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.false.%d\n", seq);
printf(" push 1\n");
printf(" jmp .L.end.%d\n", seq);
printf(".L.false.%d:\n", seq);
printf(" push 0\n");
printf(".L.end.%d:\n", seq);
return;
}
case ND_LOGOR: {
int seq = labelseq++;
gen(node->lhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" jne .L.true.%d\n", seq);
gen(node->rhs);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" jne .L.true.%d\n", seq);
printf(" push 0\n");
printf(" jmp .L.end.%d\n", seq);
printf(".L.true.%d:\n", seq);
printf(" push 1\n");
printf(".L.end.%d:\n", seq);
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++;
int brk = brkseq;
int cont = contseq;
brkseq = contseq = seq;
printf(".L.continue.%d:\n", seq);
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.break.%d\n", seq);
gen(node->then);
printf(" jmp .L.continue.%d\n", seq);
printf(".L.break.%d:\n", seq);
brkseq = brk;
contseq = cont;
return;
}
case ND_FOR: {
int seq = labelseq++;
int brk = brkseq;
int cont = contseq;
brkseq = contseq = seq;
if (node->init)
gen(node->init);
printf(".L.begin.%d:\n", seq);
if (node->cond) {
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" je .L.break.%d\n", seq);
}
gen(node->then);
printf(".L.continue.%d:\n", seq);
if (node->inc)
gen(node->inc);
printf(" jmp .L.begin.%d\n", seq);
printf(".L.break.%d:\n", seq);
brkseq = brk;
contseq = cont;
return;
}
case ND_DO: {
int seq = labelseq++;
int brk = brkseq;
int cont = contseq;
brkseq = contseq = seq;
printf(".L.begin.%d:\n", seq);
gen(node->then);
printf(".L.continue.%d:\n", seq);
gen(node->cond);
printf(" pop rax\n");
printf(" cmp rax, 0\n");
printf(" jne .L.begin.%d\n", seq);
printf(".L.break.%d:\n", seq);
brkseq = brk;
contseq = cont;
return;
}
case ND_SWITCH: {
int seq = labelseq++;
int brk = brkseq;
brkseq = seq;
node->case_label = seq;
gen(node->cond);
printf(" pop rax\n");
for (Node *n = node->case_next; n; n = n->case_next) {
n->case_label = labelseq++;
n->case_end_label = seq;
printf(" cmp rax, %ld\n", n->val);
printf(" je .L.case.%d\n", n->case_label);
}
if (node->default_case) {
int i = labelseq++;
node->default_case->case_end_label = seq;
node->default_case->case_label = i;
printf(" jmp .L.case.%d\n", i);
}
printf(" jmp .L.break.%d\n", seq);
gen(node->then);
printf(".L.break.%d:\n", seq);
brkseq = brk;
return;
}
case ND_CASE:
printf(".L.case.%d:\n", node->case_label);
gen(node->lhs);
return;
case ND_BLOCK:
case ND_STMT_EXPR:
for (Node *n = node->body; n; n = n->next)
gen(n);
return;
case ND_BREAK:
if (brkseq == 0)
error_tok(node->tok, "stray break");
printf(" jmp .L.break.%d\n", brkseq);
return;
case ND_CONTINUE:
if (contseq == 0)
error_tok(node->tok, "stray continue");
printf(" jmp .L.continue.%d\n", contseq);
return;
case ND_GOTO:
printf(" jmp .L.label.%s.%s\n", funcname, node->label_name);
return;
case ND_LABEL:
printf(".L.label.%s.%s:\n", funcname, node->label_name);
gen(node->lhs);
return;
case ND_FUNCALL: {
if (!strcmp(node->funcname, "__builtin_va_start")) {
printf(" pop rax\n");
printf(" mov edi, dword ptr [rbp-8]\n");
printf(" mov dword ptr [rax], 0\n");
printf(" mov dword ptr [rax+4], 0\n");
printf(" mov qword ptr [rax+8], rdi\n");
printf(" mov qword ptr [rax+16], 0\n");
return;
}
int nargs = 0;
for (Node *arg = node->args; arg; arg = arg->next) {
gen(arg);
nargs++;
}
for (int i = nargs - 1; i >= 0; i--)
printf(" pop %s\n", argreg8[i]);
// We need to align RSP to a 16 byte boundary before
// calling a function because it is an ABI requirement.
// RAX is set to 0 for variadic function.
int seq = labelseq++;
printf(" mov rax, rsp\n");
printf(" and rax, 15\n");
printf(" jnz .L.call.%d\n", seq);
printf(" mov rax, 0\n");
printf(" call %s\n", node->funcname);
printf(" jmp .L.end.%d\n", seq);
printf(".L.call.%d:\n", seq);
printf(" sub rsp, 8\n");
printf(" mov rax, 0\n");
printf(" call %s\n", node->funcname);
printf(" add rsp, 8\n");
printf(".L.end.%d:\n", seq);
if (node->ty->kind == TY_BOOL)
printf(" movzb rax, al\n");
printf(" push rax\n");
return;
}
case ND_RETURN:
if (node->lhs) {
gen(node->lhs);
printf(" pop rax\n");
}
printf(" jmp .L.return.%s\n", funcname);
return;
case ND_CAST:
gen(node->lhs);
truncate(node->ty);
return;
}
gen(node->lhs);
gen(node->rhs);
gen_binary(node);
}
static void emit_data(Program *prog) {
for (VarList *vl = prog->globals; vl; vl = vl->next)
if (!vl->var->is_static)
printf(".global %s\n", vl->var->name);
printf(".bss\n");
for (VarList *vl = prog->globals; vl; vl = vl->next) {
Var *var = vl->var;
if (var->initializer)
continue;
printf(".align %d\n", var->ty->align);
printf("%s:\n", var->name);
printf(" .zero %d\n", var->ty->size);
}
printf(".data\n");
for (VarList *vl = prog->globals; vl; vl = vl->next) {
Var *var = vl->var;
if (!var->initializer)
continue;
printf(".align %d\n", var->ty->align);
printf("%s:\n", var->name);
for (Initializer *init = var->initializer; init; init = init->next) {
if (init->label)
printf(" .quad %s%+ld\n", init->label, init->addend);
else if (init->sz == 1)
printf(" .byte %ld\n", init->val);
else
printf(" .%dbyte %ld\n", init->sz, init->val);
}
}
}
static void load_arg(Var *var, int idx) {
int sz = var->ty->size;
if (sz == 1) {
printf(" mov [rbp-%d], %s\n", var->offset, argreg1[idx]);
} else if (sz == 2) {
printf(" mov [rbp-%d], %s\n", var->offset, argreg2[idx]);
} else if (sz == 4) {
printf(" mov [rbp-%d], %s\n", var->offset, argreg4[idx]);
} else {
assert(sz == 8);
printf(" mov [rbp-%d], %s\n", var->offset, argreg8[idx]);
}
}
static void emit_text(Program *prog) {
printf(".text\n");
for (Function *fn = prog->fns; fn; fn = fn->next) {
if (!fn->is_static)
printf(".global %s\n", fn->name);
printf("%s:\n", fn->name);
funcname = fn->name;
// Prologue
printf(" push rbp\n");
printf(" mov rbp, rsp\n");
printf(" sub rsp, %d\n", fn->stack_size);
// Save arg registers if function is variadic
if (fn->has_varargs) {
int n = 0;
for (VarList *vl = fn->params; vl; vl = vl->next)
n++;
printf("mov dword ptr [rbp-8], %d\n", n * 8);
printf("mov [rbp-16], r9\n");
printf("mov [rbp-24], r8\n");
printf("mov [rbp-32], rcx\n");
printf("mov [rbp-40], rdx\n");
printf("mov [rbp-48], rsi\n");
printf("mov [rbp-56], rdi\n");
}
// Push arguments to the stack
int i = 0;
for (VarList *vl = fn->params; vl; vl = vl->next)
load_arg(vl->var, i++);
// Emit code
for (Node *node = fn->node; node; node = node->next)
gen(node);
// Epilogue
printf(".L.return.%s:\n", funcname);
printf(" mov rsp, rbp\n");
printf(" pop rbp\n");
printf(" ret\n");
}
}
void codegen(Program *prog) {
printf(".intel_syntax noprefix\n");
emit_data(prog);
emit_text(prog);
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/cxc123456/chibicc.git
git@gitee.com:cxc123456/chibicc.git
cxc123456
chibicc
chibicc
historical/old

搜索帮助