From e810fd2cd260ecc825599e0098aec1d1916b63c8 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Wed, 28 Apr 2021 13:44:49 -0400 Subject: [PATCH] started fleshing out a C backend --- cerise/backend/c99/codegen.c | 185 ++++++++++++++++++++++++++++++++ cerise/backend/test/codegen.c | 4 +- cerise/backend/x86_64/codegen.c | 18 +--- cerise/build.sh | 17 +-- cerise/inc/cerise.h | 5 +- cerise/src/const_ops.c | 5 + cerise/src/parser.c | 3 +- cerise/tests/Module.m | 26 +++-- cerise/tests/Module.s | 37 +------ 9 files changed, 225 insertions(+), 75 deletions(-) create mode 100644 cerise/backend/c99/codegen.c diff --git a/cerise/backend/c99/codegen.c b/cerise/backend/c99/codegen.c new file mode 100644 index 0000000..1d8da23 --- /dev/null +++ b/cerise/backend/c99/codegen.c @@ -0,0 +1,185 @@ +#include "cerise.h" +#include +#include + +Type BoolType = { + .form = FORM_BOOL, + .size = sizeof(bool) +}; + +Type IntType = { + .form = FORM_INT, + .size = sizeof(long) +}; + +Type RealType = { + .form = FORM_REAL, + .size = sizeof(double) +}; + +Type StringType = { + .form = FORM_STRING, + .size = -1 +}; + +static char* TypeNames[] = { + [FORM_BOOL] = "bool", + [FORM_INT] = "long", + [FORM_REAL] = "double", + [FORM_STRING] = "char*" +}; + +static char* BinaryOps[] = { + ['+'] = "+", + ['-'] = "-", + ['*'] = "*", + ['/'] = "/", + ['%'] = "%", +}; + +static void load_var(Parser* p, Item* item) +{ + (void)p; + switch (item->mode) + { + case ITEM_CONST: + /* TODO: range check the constant */ + printf(" const %s _T%d = %lld;\n", + TypeNames[item->type->form], p->curr_reg, item->imm.i); + item->reg = p->curr_reg; + p->curr_reg++; + + case ITEM_VAR: + break; + + case ITEM_MVAR: + /* TODO: range check the constant */ + printf(" const %s _T%d = %s_%s;\n", + TypeNames[item->type->form], p->curr_reg, p->name, item->imm.s); + item->reg = p->curr_reg; + p->curr_reg++; + break; + + case ITEM_REG: + /* nothing to do */ + break; + } +} + +/* Operators + *****************************************************************************/ +void binary_op(Parser* p, int op, Item* a, Item* b) +{ + char* type = TypeNames[a->type->form]; + char* oper = BinaryOps[op]; + printf(" const %s _T%d = _T%d %s _T%d;\n", + type, p->curr_reg, a->reg, oper, b->reg); + a->reg = p->curr_reg; + p->curr_reg++; +} + +/* Public Interface + *****************************************************************************/ +void codegen_setint(Item* item, Type* type, long long val) +{ + item->mode = ITEM_CONST; + item->type = type; + item->reg = 0; + item->imm.i = val; +} + +void codegen_setreal(Item* item, double val) +{ + item->mode = ITEM_CONST; + item->type = &RealType; + item->reg = 0; + item->imm.f = val; +} + +void codegen_setstr(Item* item, char* val) +{ + item->mode = ITEM_CONST; + item->type = &StringType; + item->reg = 0; + item->imm.s = val; +} + +void codegen_imports(Parser* p) +{ + (void)p; +} + +void codegen_global(Parser* p, char* name, Type* type) +{ + printf("%s %s_%s;\n", TypeNames[type->form], p->name, name); +} + +void codegen_main(Parser* p) +{ + (void)p; + printf("\nint main(int argc, char** argv) {\n"); + printf(" (void)argc, (void)argv;\n"); + printf(" return 0;\n"); + printf("}\n"); +} + +void codegen_startproc(Parser* p, char* name, bool exported) +{ + char* export = (exported ? "" : "static"); + if (!name) + { + printf("\n%svoid %s(void) {\n", export, p->name); + } + else + { + assert(!"not implemented"); + } +} + +void codegen_endproc(Parser* p) +{ + printf("}\n"); + (void)p; +} + +void codegen_unop(Parser* p, int op, Item* a) +{ + if (a->mode == ITEM_CONST) + { + const_unop(p, op, a); + } + else + { + assert(!"not supported"); + } +} + +void codegen_binop(Parser* p, int op, Item* a, Item* b) +{ + if (items_const(a, b)) + { + const_binop(op, a, b); + } + else + { + load_var(p, a); + load_var(p, b); + binary_op(p, op, a, b); + } +} + +void codegen_store(Parser* p, Item* a, Item* b) +{ + if (a->mode == ITEM_MVAR && b->reg == 0) + { + printf(" %s_%s = %lld;\n", p->name, a->imm.s, b->imm.i); + } + else if (a->mode == ITEM_MVAR) + { + printf(" %s_%s = _T%d;\n", p->name, a->imm.s, b->reg); + } + else + { + assert(!"bad store op"); + } +} diff --git a/cerise/backend/test/codegen.c b/cerise/backend/test/codegen.c index b52c404..fa252c6 100644 --- a/cerise/backend/test/codegen.c +++ b/cerise/backend/test/codegen.c @@ -61,9 +61,9 @@ void codegen_main(Parser* p) (void)p; } -void codegen_startproc(Parser* p, char* name, long long localsz) +void codegen_startproc(Parser* p, char* name, bool exported) { - (void)p, (void)name, (void)localsz; + (void)p, (void)name, (void)exported; } void codegen_endproc(Parser* p) diff --git a/cerise/backend/x86_64/codegen.c b/cerise/backend/x86_64/codegen.c index ee68ad4..ac961a6 100644 --- a/cerise/backend/x86_64/codegen.c +++ b/cerise/backend/x86_64/codegen.c @@ -177,11 +177,6 @@ void codegen_setstr(Item* item, char* val) item->imm.s = val; } -static int items_const(Item* a, Item* b) -{ - return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); -} - static void load_var(Parser* p, Item* item) { (void)p; @@ -241,7 +236,7 @@ void codegen_main(Parser* p) printf(" ret\n"); } -void codegen_startproc(Parser* p, char* name, long long localsz) +void codegen_startproc(Parser* p, char* name, bool exported) { printf(" .text\n"); if (name) @@ -254,17 +249,8 @@ void codegen_startproc(Parser* p, char* name, long long localsz) printf(" .globl %s\n", p->name); printf("%s:\n", p->name); } - printf(" pushq %%rbp\n"); - if (localsz > 0) - { - printf(" movq %%rsp, %%rbp\n"); - printf(" sub $%lld, %%rsp\n\n", localsz); - } - else - { - printf(" movq %%rsp, %%rbp\n\n"); - } + printf(" movq %%rsp, %%rbp\n\n"); p->curr_reg = 1; } diff --git a/cerise/build.sh b/cerise/build.sh index 55e2765..258525a 100755 --- a/cerise/build.sh +++ b/cerise/build.sh @@ -1,14 +1,15 @@ #!/bin/sh CCCMD="cc -g -Wall -Wextra --std=c99 -Iinc/" -BACKEND=backend/x86_64 TEST_BACKEND=backend/test ctags -R & -$CCCMD -D CERISE_TESTS -o cerisec-test src/*.c "$TEST_BACKEND"/*.c \ - && $CCCMD -o cerisec src/*.c "$BACKEND"/*.c \ - && ./cerisec-test \ - && ./cerisec tests/Module.m | tee tests/Module.s \ - && cc -o Module tests/Module.s -rm Module -#[ $? -gt 0 ] && printf "\a" + + $CCCMD -D CERISE_TESTS -o cerisec-test src/*.c backend/test/*.c \ +&& $CCCMD -o cerisec src/*.c "backend/c99"/*.c \ +&& $CCCMD -o cerisec-x86_64 src/*.c "backend/x86_64"/*.c \ +&& ./cerisec-test \ +&& ./cerisec tests/Module.m + +rm -f Module + diff --git a/cerise/inc/cerise.h b/cerise/inc/cerise.h index 9632861..84ee627 100644 --- a/cerise/inc/cerise.h +++ b/cerise/inc/cerise.h @@ -131,7 +131,7 @@ typedef struct { Module* imports; Symbol* scope; char* name; - long curr_reg; + int curr_reg; } Parser; static inline void item_dump(Item* a) @@ -162,6 +162,7 @@ void compile(char* fname); /* Code Generation *****************************************************************************/ +int items_const(Item* a, Item* b); void const_binop(int op, Item* a, Item* b); void const_unop(Parser* p, int op, Item* a); @@ -174,7 +175,7 @@ void codegen_setstr(Item* item, char* val); void codegen_imports(Parser* p); void codegen_global(Parser* p, char* name, Type* type); void codegen_main(Parser* p); -void codegen_startproc(Parser* p, char* name, long long localsz); +void codegen_startproc(Parser* p, char* name, bool exported); void codegen_endproc(Parser* p); void codegen_unop(Parser* p, int op, Item* a); void codegen_binop(Parser* p, int op, Item* a, Item* b); diff --git a/cerise/src/const_ops.c b/cerise/src/const_ops.c index a627336..eedd955 100644 --- a/cerise/src/const_ops.c +++ b/cerise/src/const_ops.c @@ -1,5 +1,10 @@ #include "cerise.h" +int items_const(Item* a, Item* b) +{ + return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); +} + void const_binop(int op, Item* a, Item* b) { if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) diff --git a/cerise/src/parser.c b/cerise/src/parser.c index fed4f03..0c6f746 100644 --- a/cerise/src/parser.c +++ b/cerise/src/parser.c @@ -597,7 +597,6 @@ RULE(statement_seq) init_item(item, sym); item->imm.s = sym->name; - printf("\n// %s = ...\n", sym->name); expression(p, &right); check_types(p, item, &right); codegen_store(p, item, &right); @@ -685,7 +684,7 @@ RULE(module) var_decl(p, item); } - codegen_startproc(p, NULL, 0); + codegen_startproc(p, NULL, true); if (accept(p, BEGIN)) { codegen_imports(p); diff --git a/cerise/tests/Module.m b/cerise/tests/Module.m index f33cbfd..960e45c 100644 --- a/cerise/tests/Module.m +++ b/cerise/tests/Module.m @@ -14,25 +14,29 @@ var c : Int begin -# a = true; -# a = A; -# b = 24; -# b = B; + a = true; + a = A; + b = 24; + b = B; + + # Unary ops +# b = +b; +# b = -b; # Immediate ops c = b + 1; -# c = b - 1; -# c = b * 1; + c = b - 1; + c = b * 1; # c = b == 1; # Register ops -# c = 1 + b; -# c = 1 - b; -# c = 1 * b; + c = 1 + b; + c = 1 - b; + c = 1 * b; -# c = b + b; + c = b + b; # Complex arithmetic -# c = b + b * b + b + c = b + b * b + b; end diff --git a/cerise/tests/Module.s b/cerise/tests/Module.s index d39ed31..6c0af9f 100644 --- a/cerise/tests/Module.s +++ b/cerise/tests/Module.s @@ -1,36 +1,5 @@ - .data -Module_a: - .zero 1 - - .data -Module_b: - .zero 8 - - .data -Module_c: - .zero 8 - - .text - .globl Module -Module: - pushq %rbp - movq %rsp, %rbp - +a +b +c // c = ... - movq Module_b(%rip), %rdi - addq $1, %rdi - movq %rdi, Module_c(%rip) - - pop %rbp - ret - - .text - .globl main -main: - pushq %rbp - movq %rsp, %rbp - call Module - xor %rax, %rax - pop %rbp - ret -- 2.49.0