From 5813216edbbba68405e23919f5d76b91f06290bd Mon Sep 17 00:00:00 2001 From: mike lowis Date: Tue, 27 Apr 2021 23:03:00 -0400 Subject: [PATCH] added more operations --- cerise/cerise.h | 6 +- cerise/codegen.c | 373 +++++++++++++++--------------------------- cerise/const_ops.c | 137 ++++++++++++++++ cerise/tests/Module.m | 16 +- cerise/tests/Module.s | 7 +- 5 files changed, 284 insertions(+), 255 deletions(-) create mode 100644 cerise/const_ops.c diff --git a/cerise/cerise.h b/cerise/cerise.h index c784aaf..9632861 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -162,10 +162,8 @@ void compile(char* fname); /* Code Generation *****************************************************************************/ -enum Regs { - NOREG, RBX, RCX, RDX, RBP, RSP, RSI, RDI, - R8, R9, R10, R11, R12, R13, R14, R15, -}; +void const_binop(int op, Item* a, Item* b); +void const_unop(Parser* p, int op, Item* a); extern Type BoolType, IntType, RealType, StringType; diff --git a/cerise/codegen.c b/cerise/codegen.c index 8e2f452..4997696 100644 --- a/cerise/codegen.c +++ b/cerise/codegen.c @@ -2,234 +2,184 @@ #include #include -#define MAX_REG 15 - -/* Register Usage - -*/ - -Type BoolType = { - .form = FORM_BOOL, - .size = sizeof(bool) +static char* RegNames[] = { + "%noreg", // invalid register + "%rdi", // 1st argument + "%rsi", // 2nd argument + "%rdx", // 3rd argument + "%rcx", // 4th argument + "%r8", // 5th argument + "%r9", // 6th argument + "%rbx", // temp register + "%r10", // temp register + "%r11", // temp register + "%r12", // callee saved register + "%r13", // callee saved register + "%r14", // callee saved register + "%r15", // callee saved register +// "%rax", // return value }; -Type IntType = { - .form = FORM_INT, - .size = sizeof(long) -}; +#define MAX_REG (int)(sizeof(RegNames)/sizeof(RegNames[0])) -Type RealType = { - .form = FORM_REAL, - .size = sizeof(double) -}; - -Type StringType = { - .form = FORM_STRING, - .size = -1 -}; +static char* regname(int reg) +{ + return RegNames[reg]; +} -void codegen_setint(Item* item, Type* type, long long val) +static char* curr_regname(Parser* p) { - item->mode = ITEM_CONST; - item->type = type; - item->reg = NOREG; - item->imm.i = val; + return regname(p->curr_reg); } -void codegen_setreal(Item* item, double val) +static void next_reg(Parser* p) { - item->mode = ITEM_CONST; - item->type = &RealType; - item->reg = NOREG; - item->imm.f = val; + if (p->curr_reg < MAX_REG) + { + p->curr_reg++; + } + else + { + assert(!"register stack overflow"); + } } -void codegen_setstr(Item* item, char* val) +static void put_immop(char* op, int reg, long long imm) { - item->mode = ITEM_CONST; - item->type = &StringType; - item->reg = NOREG; - item->imm.s = val; + printf(" %s $%lld, %s\n", op, imm, regname(reg)); } -static int items_const(Item* a, Item* b) +static void put_regop(char* op, int rega, int regb) { - return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); + printf(" %s %s, %s\n", op, regname(regb), regname(rega)); } -static void const_binop(int op, Item* a, Item* b) +static void imm_binop(Parser* p, int op, Item* a, Item* b) { + (void)p; if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) { switch (op) { - case '+': a->imm.i = a->imm.i + b->imm.i; break; - case '-': a->imm.i = a->imm.i - b->imm.i; break; - case '*': a->imm.i = a->imm.i * b->imm.i; break; - case '/': a->imm.i = a->imm.i / b->imm.i; break; - case '%': a->imm.i = a->imm.i % b->imm.i; break; - case AND: a->imm.i = a->imm.i && b->imm.i; break; - case OR: a->imm.i = a->imm.i || b->imm.i; break; - - case EQ: - a->imm.i = a->imm.i == b->imm.i; - a->type = &BoolType; - break; - - case NEQ: - a->imm.i = a->imm.i != b->imm.i; - a->type = &BoolType; + case '+': + put_immop("addq", a->reg, b->imm.i); break; - case '<': - a->imm.i = a->imm.i < b->imm.i; - a->type = &BoolType; + case '-': + put_immop("subq", a->reg, b->imm.i); break; - case LTEQ: - a->imm.i = a->imm.i <= b->imm.i; - a->type = &BoolType; + case '*': + put_immop("imulq", a->reg, b->imm.i); break; - case '>': - a->imm.i = a->imm.i > b->imm.i; - a->type = &BoolType; - break; - - case GTEQ: - a->imm.i = a->imm.i >= b->imm.i; - a->type = &BoolType; - break; - -// case IS: break; - +// case '/': +// case '%': +// case AND: +// case OR: + +// case EQ: +// cmpq %rax, %rdx +// setl %al +// movzbl %al, %eax +// case NEQ: +// case '<': +// case LTEQ: +// case '>': +// case GTEQ: default: - assert(!"not a valid op"); - break; + assert(!"unimplemented immediate op"); } } - else if (a->type->form == FORM_REAL) + else + { + assert(!"not implemented"); + } +} + +static void reg_binop(Parser* p, int op, Item* a, Item* b) +{ + if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) { switch (op) { - case '+': a->imm.f = a->imm.f + b->imm.f; break; - case '-': a->imm.f = a->imm.f - b->imm.f; break; - case '*': a->imm.f = a->imm.f * b->imm.f; break; - case '/': a->imm.f = a->imm.f / b->imm.f; break; - - case EQ: - a->imm.f = a->imm.f == b->imm.f; - a->type = &BoolType; - break; - - case NEQ: - a->imm.f = a->imm.f != b->imm.f; - a->type = &BoolType; + case '+': + put_regop("addq", a->reg, b->reg); break; - case '<': - a->imm.f = a->imm.f < b->imm.f; - a->type = &BoolType; + case '-': + put_regop("subq", a->reg, b->reg); break; - case LTEQ: - a->imm.f = a->imm.f <= b->imm.f; - a->type = &BoolType; - break; - - case '>': - a->imm.f = a->imm.f > b->imm.f; - a->type = &BoolType; - break; - - case GTEQ: - a->imm.f = a->imm.f >= b->imm.f; - a->type = &BoolType; + case '*': + put_regop("imulq", a->reg, b->reg); break; +// case '/': +// case '%': +// case AND: +// case OR: + +// case EQ: +// case NEQ: +// case '<': +// case LTEQ: +// case '>': +// case GTEQ: default: - assert(!"not a valid op"); - break; + assert(!"unimplemented immediate op"); } - } - else - { - assert(!"not a valid form"); + p->curr_reg--; } } -static void const_unop(Parser* p, int op, Item* a) +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 +}; + +void codegen_setint(Item* item, Type* type, long long val) { - (void)p; - if (a->type->form == FORM_INT) - { - switch (op) - { - case '+': a->imm.i = +a->imm.i; break; - case '-': a->imm.i = -a->imm.i; break; - default: assert(!"not a valid op"); break; - } - } - else if (a->type->form == FORM_REAL) - { - switch (op) - { - case '+': a->imm.f = +a->imm.f; break; - case '-': a->imm.f = -a->imm.f; break; - default: assert(!"not a valid op"); break; - } - } - else if (a->type->form == FORM_BOOL) - { - switch (op) - { - case NOT: a->imm.i = !a->imm.i; break; - default: assert(!"not a valid op"); break; - } - } - else - { - assert(!"not a valid form"); - } + item->mode = ITEM_CONST; + item->type = type; + item->reg = 0; + item->imm.i = val; } -static char* regname(int reg) +void codegen_setreal(Item* item, double val) { - static char* names[] = { - "%noreg", // invalid register - "%rdi", // 1st argument - "%rsi", // 2nd argument - "%rdx", // 3rd argument - "%rcx", // 4th argument - "%r8", // 5th argument - "%r9", // 6th argument - "%rbx", // temp register - "%r10", // temp register - "%r11", // temp register - "%r12", // callee saved register - "%r13", // callee saved register - "%r14", // callee saved register - "%r15", // callee saved register - "%rax", // return value - }; - return names[reg]; + item->mode = ITEM_CONST; + item->type = &RealType; + item->reg = 0; + item->imm.f = val; } -static char* curr_regname(Parser* p) +void codegen_setstr(Item* item, char* val) { - return regname(p->curr_reg); + item->mode = ITEM_CONST; + item->type = &StringType; + item->reg = 0; + item->imm.s = val; } -static void next_reg(Parser* p) +static int items_const(Item* a, Item* b) { - if (p->curr_reg < MAX_REG) - { - p->curr_reg++; - } - else - { - assert(!"register stack overflow"); - } + return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); } static void load_var(Parser* p, Item* item) @@ -239,10 +189,7 @@ static void load_var(Parser* p, Item* item) { case ITEM_CONST: /* TODO: range check the constant */ -// // emit instruction -// item->reg = p->curr_reg; - - printf(" movq %s, $%lld\n", curr_regname(p), item->imm.i); + put_immop("movq", p->curr_reg, item->imm.i); item->reg = p->curr_reg; next_reg(p); break; @@ -253,17 +200,13 @@ static void load_var(Parser* p, Item* item) case ITEM_MVAR: // puts("MVAR"); // printf("movq %s, $%lld\n", curr_regname(p), item->imm.i); - // item_dump(item); - printf(" movq %s_%s(%%rip), %s\n", p->name, item->imm.s, curr_regname(p) ); -// b->imm.i, p->name, a->imm.s); - item->reg = p->curr_reg; next_reg(p); break; @@ -349,44 +292,6 @@ void codegen_unop(Parser* p, int op, Item* a) } } -static char* ImmOps[] = { - ['+'] = "addq", -}; - -static void imm_binop(Parser* p, int op, Item* a, Item* b) -{ - if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) - { - char* opstring = ImmOps[op]; - if (a->mode == ITEM_CONST) - { -// printf(" %s $%lld, %s\n", -// opstring, regname(b->reg), a->imm.i, regname(b->reg)); - printf(" %s $%lld, %s\n", - opstring, a->imm.i, regname(b->reg)); - a->reg = b->reg; - } - else - { - printf(" %s $%lld, %s\n", - opstring, b->imm.i, regname(a->reg)); - } - } - else - { - assert(!"not implemented"); - } -} - -static void imm_regop(Parser* p, int op, Item* a, Item* b) -{ - if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) - { - printf(" addq %s, %s, %s\n", - regname(a->reg), regname(b->reg), regname(b->reg)); - } -} - void codegen_binop(Parser* p, int op, Item* a, Item* b) { if (items_const(a, b)) @@ -399,39 +304,19 @@ void codegen_binop(Parser* p, int op, Item* a, Item* b) imm_binop(p, op, a, b); p->curr_reg--; } - else if (a->mode == ITEM_CONST) - { - load_var(p, b); - imm_binop(p, op, a, b); - p->curr_reg--; - } else { load_var(p, a); load_var(p, b); - item_dump(a); - item_dump(b); - - imm_regop(p, op, a, b); - - // emit instruction - // p->topreg--; - // a->reg = p->topreg-1; + reg_binop(p, op, a, b); + p->curr_reg--; + a->reg = p->curr_reg; } } -// PROCEDURE Switch*(VAR x: Item); -// BEGIN Put1(Mov, RH, 0, -60); Put2(Ldw, RH, RH, 0); -// x.mode := Reg; -// x.type := intType; -// x.r := RH; -// INC(RH) -// END Switch; - - void codegen_store(Parser* p, Item* a, Item* b) { - if (a->mode == ITEM_MVAR && b->reg == NOREG) + if (a->mode == ITEM_MVAR && b->reg == 0) { printf(" movq $%lld, %s_%s(%%rip)\n", b->imm.i, p->name, a->imm.s); diff --git a/cerise/const_ops.c b/cerise/const_ops.c new file mode 100644 index 0000000..a627336 --- /dev/null +++ b/cerise/const_ops.c @@ -0,0 +1,137 @@ +#include "cerise.h" + +void const_binop(int op, Item* a, Item* b) +{ + if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) + { + switch (op) + { + case '+': a->imm.i = a->imm.i + b->imm.i; break; + case '-': a->imm.i = a->imm.i - b->imm.i; break; + case '*': a->imm.i = a->imm.i * b->imm.i; break; + case '/': a->imm.i = a->imm.i / b->imm.i; break; + case '%': a->imm.i = a->imm.i % b->imm.i; break; + case AND: a->imm.i = a->imm.i && b->imm.i; break; + case OR: a->imm.i = a->imm.i || b->imm.i; break; + + case EQ: + a->imm.i = a->imm.i == b->imm.i; + a->type = &BoolType; + break; + + case NEQ: + a->imm.i = a->imm.i != b->imm.i; + a->type = &BoolType; + break; + + case '<': + a->imm.i = a->imm.i < b->imm.i; + a->type = &BoolType; + break; + + case LTEQ: + a->imm.i = a->imm.i <= b->imm.i; + a->type = &BoolType; + break; + + case '>': + a->imm.i = a->imm.i > b->imm.i; + a->type = &BoolType; + break; + + case GTEQ: + a->imm.i = a->imm.i >= b->imm.i; + a->type = &BoolType; + break; + +// case IS: break; + + default: + assert(!"not a valid op"); + break; + } + } + else if (a->type->form == FORM_REAL) + { + switch (op) + { + case '+': a->imm.f = a->imm.f + b->imm.f; break; + case '-': a->imm.f = a->imm.f - b->imm.f; break; + case '*': a->imm.f = a->imm.f * b->imm.f; break; + case '/': a->imm.f = a->imm.f / b->imm.f; break; + + case EQ: + a->imm.f = a->imm.f == b->imm.f; + a->type = &BoolType; + break; + + case NEQ: + a->imm.f = a->imm.f != b->imm.f; + a->type = &BoolType; + break; + + case '<': + a->imm.f = a->imm.f < b->imm.f; + a->type = &BoolType; + break; + + case LTEQ: + a->imm.f = a->imm.f <= b->imm.f; + a->type = &BoolType; + break; + + case '>': + a->imm.f = a->imm.f > b->imm.f; + a->type = &BoolType; + break; + + case GTEQ: + a->imm.f = a->imm.f >= b->imm.f; + a->type = &BoolType; + break; + + default: + assert(!"not a valid op"); + break; + } + } + else + { + assert(!"not a valid form"); + } +} + +void const_unop(Parser* p, int op, Item* a) +{ + (void)p; + if (a->type->form == FORM_INT) + { + switch (op) + { + case '+': a->imm.i = +a->imm.i; break; + case '-': a->imm.i = -a->imm.i; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_REAL) + { + switch (op) + { + case '+': a->imm.f = +a->imm.f; break; + case '-': a->imm.f = -a->imm.f; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_BOOL) + { + switch (op) + { + case NOT: a->imm.i = !a->imm.i; break; + default: assert(!"not a valid op"); break; + } + } + else + { + assert(!"not a valid form"); + } +} diff --git a/cerise/tests/Module.m b/cerise/tests/Module.m index de35273..f33cbfd 100644 --- a/cerise/tests/Module.m +++ b/cerise/tests/Module.m @@ -18,7 +18,21 @@ begin # a = A; # b = 24; # b = B; + + # Immediate ops c = b + 1; - c = 1 + b; +# c = b - 1; +# c = b * 1; + +# c = b == 1; + + # Register ops +# c = 1 + b; +# c = 1 - b; +# c = 1 * b; + # c = b + b; + + # Complex arithmetic +# c = b + b * b + b end diff --git a/cerise/tests/Module.s b/cerise/tests/Module.s index 8ef8b9e..d39ed31 100644 --- a/cerise/tests/Module.s +++ b/cerise/tests/Module.s @@ -19,12 +19,7 @@ Module: // c = ... movq Module_b(%rip), %rdi - addq $1, %rdi - movq %rdi, Module_c(%rip) - -// c = ... - movq Module_b(%rip), %rdi - addq $1, %rdi + addq $1, %rdi movq %rdi, Module_c(%rip) pop %rbp -- 2.49.0