From feb623ab014f6d31a2252ab7e2460125ea2865ee Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 20 Jul 2021 23:30:09 -0400 Subject: [PATCH] constant folding working for new ssa form --- cerise/src/ast.c | 1150 ++++++++++++++++++++--------------------- cerise/src/grammar.c | 2 +- cerise/src/ssa.c | 192 ++++++- cerise/tests/Module.m | 8 +- 4 files changed, 750 insertions(+), 602 deletions(-) diff --git a/cerise/src/ast.c b/cerise/src/ast.c index 403445f..d8de21b 100644 --- a/cerise/src/ast.c +++ b/cerise/src/ast.c @@ -36,578 +36,578 @@ Basic Block */ -#if 0 -AstNode* ast_bool(AstNode* block, bool val); -AstNode* ast_int(AstNode* block, long long val); -AstNode* ast_real(AstNode* block, double val); -AstNode* ast_ident(AstNode* block, Parser* p, long long index); -AstNode* ast_op(AstNode* block, int op, AstNode* left, AstNode* right); -AstNode* ast_store(AstNode* block, AstNode* dest, AstNode* offset, AstNode* value); -AstNode* ast_return(AstNode* block, AstNode* expr, AstNode* dest); -AstNode* ast_if(AstNode* block, AstNode* cond, AstNode* dest1, AstNode* dest2); -// while -// foreach -// case - -/* identifier references and literal values */ -typedef struct { - AstNodeHeader hdr; - union { - long long i; - double f; - char* s; - } val; - long long tag; -} AstValue; - -typedef struct { - AstNodeHeader hdr; - AstNode* dest; - AstNode* left; - AstNode* right; -} AstOp; - -typedef struct { - AstNodeHeader hdr; - AstNode* head; - AstNode* tail; -} AstBlock; - -#else - -typedef struct { - AstNodeHeader hdr; - union { - long long i; - double f; - char* s; - } val; - long long tag; -} AstValue; - -#endif - -bool ast_isconst(AstNode* node) -{ - bool ret; - switch (node->hdr.code) - { - case BOOL: - case INT: - case REAL: - ret = true; - break; - - default: - ret = false; - break; - } - return ret; -} - -bool ast_areconst(AstNode* left, AstNode* right) -{ - return ast_isconst(left) && ast_isconst(right); -} - -static AstNode* ast_new(int code, Type* type, AstNode* l0, AstNode* l1, AstNode* l2) -{ - AstNode* node = calloc(1, sizeof(AstNode)); - node->hdr.code = code; - node->hdr.type = type; - node->links[0] = l0; - node->links[1] = l1; - node->links[2] = l2; - return node; -} - -static AstNode* ast_clone(AstNode* parent) -{ - AstNode* node = calloc(1, sizeof(AstNode)); - *node = *parent; - return node; -} - -AstNode* ast_ident(Parser* p, long long index) -{ - Symbol* sym = symbol_getbyid(p, (size_t)index); - AstNode* node; - if (sym && sym->class == SYM_CONST) - { - assert(sym->value != NULL); - node = ast_clone(sym->value); - } - else - { - node = ast_new(IDENT, sym->type, NULL, NULL, NULL); - ((AstValue*)node)->val.i = index; - } - return (AstNode*)node; -} - -AstNode* ast_bool(Parser* p, bool val) -{ - (void)p; - AstValue* node = (AstValue*)ast_new(BOOL, &BoolType, NULL, NULL, NULL); - node->val.i = val; - return (AstNode*)node; -} - -AstNode* ast_int(Parser* p, long long val) -{ - (void)p; - AstValue* node = (AstValue*)ast_new(INT, &IntType, NULL, NULL, NULL); - node->val.i = val; - return (AstNode*)node; -} - -AstNode* ast_real(Parser* p, double val) -{ - (void)p; - AstValue* node = (AstValue*)ast_new(REAL, &RealType, NULL, NULL, NULL); - node->val.f = val; - return (AstNode*)node; -} - -bool ast_asbool(AstNode* node) -{ - assert(node->hdr.type->form == FORM_BOOL); - return (bool)(((AstValue*)node)->val.i); -} - -long long ast_asint(AstNode* node) -{ - assert(node->hdr.type->form == FORM_INT); - return ((AstValue*)node)->val.i; -} - -double ast_asreal(AstNode* node) -{ - assert(node->hdr.type->form == FORM_REAL); - return ((AstValue*)node)->val.f; -} - -static AstNode* ast_binop(int op, AstNode* left, AstNode* right) -{ - assert(left); - assert(right); - AstNode* ret = NULL; - if (ast_areconst(left,right)) - { - AstValue* a = (AstValue*)left; - AstValue* b = (AstValue*)right; - if (a->hdr.type->form == FORM_INT || a->hdr.type->form == FORM_BOOL) - { - switch (op) - { - case '+': a->val.i = a->val.i + b->val.i; break; - case '-': a->val.i = a->val.i - b->val.i; break; - case '*': a->val.i = a->val.i * b->val.i; break; - case '/': a->val.i = a->val.i / b->val.i; break; - case '%': a->val.i = a->val.i % b->val.i; break; - case AND: a->val.i = a->val.i && b->val.i; break; - case OR: a->val.i = a->val.i || b->val.i; break; - - case EQ: - a->val.i = a->val.i == b->val.i; - a->hdr.type = &BoolType; - break; - - case NEQ: - a->val.i = a->val.i != b->val.i; - a->hdr.type = &BoolType; - break; - - case '<': - a->val.i = a->val.i < b->val.i; - a->hdr.type = &BoolType; - break; - - case LTEQ: - a->val.i = a->val.i <= b->val.i; - a->hdr.type = &BoolType; - break; - - case '>': - a->val.i = a->val.i > b->val.i; - a->hdr.type = &BoolType; - break; - - case GTEQ: - a->val.i = a->val.i >= b->val.i; - a->hdr.type = &BoolType; - break; - - default: - assert(!"not a valid op"); - break; - } - } - else if (a->hdr.type->form == FORM_REAL) - { - switch (op) - { - case '+': a->val.f = a->val.f + b->val.f; break; - case '-': a->val.f = a->val.f - b->val.f; break; - case '*': a->val.f = a->val.f * b->val.f; break; - case '/': a->val.f = a->val.f / b->val.f; break; - - case EQ: - a->val.f = a->val.f == b->val.f; - a->hdr.type = &BoolType; - break; - - case NEQ: - a->val.f = a->val.f != b->val.f; - a->hdr.type = &BoolType; - break; - - case '<': - a->val.f = a->val.f < b->val.f; - a->hdr.type = &BoolType; - break; - - case LTEQ: - a->val.f = a->val.f <= b->val.f; - a->hdr.type = &BoolType; - break; - - case '>': - a->val.f = a->val.f > b->val.f; - a->hdr.type = &BoolType; - break; - - case GTEQ: - a->val.f = a->val.f >= b->val.f; - a->hdr.type = &BoolType; - break; - - default: - assert(!"not a valid op"); - break; - } - } - else - { - assert(!"not a valid form"); - } - ret = (AstNode*)a; - } - else - { - switch (op) - { - case EQ: - case NEQ: - case '<': - case LTEQ: - case '>': - case GTEQ: - ret = ast_new(op, &BoolType, left, right, NULL); - break; - - default: - ret = ast_new(op, left->hdr.type, left, right, NULL); - break; - } - } - return ret; -} - -static AstNode* ast_unop(int op, AstNode* operand) -{ - assert(operand); - AstNode* ret = NULL; - if (ast_isconst(operand)) - { - AstValue* a = (AstValue*)operand; - if (a->hdr.type->form == FORM_INT) - { - switch (op) - { - case '+': a->val.i = +a->val.i; break; - case '-': a->val.i = -a->val.i; break; - default: assert(!"not a valid op"); break; - } - } - else if (a->hdr.type->form == FORM_REAL) - { - switch (op) - { - case '+': a->val.f = +a->val.f; break; - case '-': a->val.f = -a->val.f; break; - default: assert(!"not a valid op"); break; - } - } - else if (a->hdr.type->form == FORM_BOOL) - { - switch (op) - { - case NOT: a->val.i = !a->val.i; break; - default: assert(!"not a valid op"); break; - } - } - else - { - assert(!"not a valid form"); - } - ret = (AstNode*)a; - } - else - { - ret = ast_new(op, operand->hdr.type, operand, NULL, NULL); - } - return ret; -} - -AstNode* ast_op(Parser* p, int op, AstNode* left, AstNode* right) -{ - (void)p; - return (right - ? ast_binop(op, left, right) - : ast_unop(op, left)); -} - -AstNode* ast_store(AstNode* dest, AstNode* value) -{ - /* TODO: validate left-hand side is assignable */ - return ast_new('=', &VoidType, dest, value, NULL); -} - -static Field* get_field(Parser* p, Type* type, char* name) -{ - Field* curr = type->fields; - while (curr) - { - if (curr->name && !strcmp(curr->name, name)) - { - break; - } - curr = curr->next; - } - if (!curr) - { - error(p, "record has no such field '%s'\n", name); - } - return curr; -} - -AstNode* ast_fieldref(Parser* p, AstNode* record, char* fname) -{ - Field* field = get_field(p, record->hdr.type, fname); - AstNode* offset = ast_int(p, field->offset); - if (record->hdr.code == '.') - { - /* accumulate the offset into an existing record access */ - record->links[1] = ast_binop('+', record->links[1], offset); - record->hdr.type = field->type; - } - else - { - /* create a new record access node */ - record = ast_new('.', field->type, record, offset, NULL); - } - return record; -} - -AstNode* ast_index(Parser* p, AstNode* array, AstNode* index) -{ - if (ast_isconst(index) && ast_asint(index) >= array->hdr.type->size) - { - error(p, "constant array index out of bounds"); - } - return ast_new('[', array->hdr.type->base, array, index, NULL); -} - -AstNode* ast_block(void) -{ - return ast_new(BEGIN, &VoidType, NULL, NULL, NULL); -} - -static void append(AstNode* node, int offset, AstNode* first, AstNode* last) -{ - if (!node->links[offset + 0]) - { - node->links[offset + 0] = first; - node->links[offset + 1] = last; - } - else - { - node->links[offset + 1]->hdr.next = first; - node->links[offset + 1] = last; - } -} - -void ast_block_add(AstNode* blk, AstNode* stmt) -{ - assert(blk->hdr.code == BEGIN); - /* if we recieve a BEGIN block, we faltten it into the block by - appending all its statemtents */ - if (stmt->hdr.code == BEGIN) - { - append(blk, 0, stmt->links[0], stmt->links[1]); - } - /* otherwise just append the statement to the block */ - else - { - append(blk, 0, stmt, stmt); - } -} - -AstNode* ast_call(AstNode* func) -{ - return ast_new(CALL, func->hdr.type, func, NULL, NULL); -} - -void ast_call_add(AstNode* func, AstNode* arg) -{ - append(func, 1, arg, arg); -} - -AstNode* ast_if(AstNode* cond, AstNode* br1, AstNode* br2) -{ - AstNode* ret; - if (ast_isconst(cond)) - { - ret = (ast_asbool(cond) ? br1 : br2); - } - else - { - ret = ast_new(IF, &VoidType, cond, br1, br2); - } - return ret; -} - -AstNode* ast_return(AstNode* expr) -{ - return ast_new(RETURN, &VoidType, expr, NULL, NULL); -} - -static void print_indent(int indent, char* str) -{ - /* print the indent */ - for (int i = 0; i < indent; i++) - { - printf(" "); - } - if (str) - { - printf("%s", str); - } -} - -static void print_opcode(AstNode* node) -{ - int op = node->hdr.code; - if (op < 256) - { - printf("(%c\n", op); - } - else if (op == RETURN) - { - printf("(return\n"); - } - else if (op == IF) - { - printf("(if\n"); - } - else - { - printf("(%d\n", op); - } -} - -static void print(Parser* p, AstNode* node, int indent) -{ - assert(node); - print_indent(indent, NULL); - - /* now print the data */ - switch(node->hdr.code) - { - case BOOL: - printf("B:%lld", ((AstValue*)node)->val.i); - break; - - case INT: - printf("I:%lld", ((AstValue*)node)->val.i); - break; - - case REAL: - printf("R:%f", ((AstValue*)node)->val.f); - break; - - case IDENT: - { - Symbol* s = symbol_getbyid(p, ((AstValue*)node)->val.i); - printf("%s.%lld", s->name, ((AstValue*)node)->tag); - } - break; - - case '.': - printf("(field-ref\n"); - print(p, node->links[0], indent+1); - print(p, node->links[1], indent+1); - print_indent(indent, ")"); - break; - - case '[': - printf("(array-index\n"); - print(p, node->links[0], indent+1); - print(p, node->links[1], indent+1); - print_indent(indent, ")"); - break; - - case BEGIN: - printf("(begin\n"); - for (AstNode* curr = node->links[0]; curr; curr = curr->hdr.next) - { - print(p, curr, indent+1); - } - print_indent(indent, ")"); - break; - - case CALL: - printf("(call\n"); - print(p, node->links[0], indent+1); - for (AstNode* curr = node->links[1]; curr; curr = curr->hdr.next) - { - print(p, curr, indent+1); - } - print_indent(indent, ")"); - break; - - case IF: - printf("(if\n"); - print(p, node->links[0], indent+1); - print(p, node->links[1], indent+1); - if (node->links[2]) - { - print(p, node->links[2], indent+1); - } - print_indent(indent, ")"); - break; - - default: - if (node->links[1]) - { - print_opcode(node); - print(p, node->links[0], indent+1); - print(p, node->links[1], indent+1); - print_indent(indent, ")"); - } - else - { - print_opcode(node); - print(p, node->links[0], indent+1); - print_indent(indent, ")"); - } - break; - } - puts(""); -} - -void ast_print(Parser* p, AstNode* node) -{ - print(p, node, 0); -} +//#if 0 +//AstNode* ast_bool(AstNode* block, bool val); +//AstNode* ast_int(AstNode* block, long long val); +//AstNode* ast_real(AstNode* block, double val); +//AstNode* ast_ident(AstNode* block, Parser* p, long long index); +//AstNode* ast_op(AstNode* block, int op, AstNode* left, AstNode* right); +//AstNode* ast_store(AstNode* block, AstNode* dest, AstNode* offset, AstNode* value); +//AstNode* ast_return(AstNode* block, AstNode* expr, AstNode* dest); +//AstNode* ast_if(AstNode* block, AstNode* cond, AstNode* dest1, AstNode* dest2); +//// while +//// foreach +//// case + +///* identifier references and literal values */ +//typedef struct { +// AstNodeHeader hdr; +// union { +// long long i; +// double f; +// char* s; +// } val; +// long long tag; +//} AstValue; +// +//typedef struct { +// AstNodeHeader hdr; +// AstNode* dest; +// AstNode* left; +// AstNode* right; +//} AstOp; +// +//typedef struct { +// AstNodeHeader hdr; +// AstNode* head; +// AstNode* tail; +//} AstBlock; +// +//#else +// +//typedef struct { +// AstNodeHeader hdr; +// union { +// long long i; +// double f; +// char* s; +// } val; +// long long tag; +//} AstValue; +// +//#endif +// +//bool ast_isconst(AstNode* node) +//{ +// bool ret; +// switch (node->hdr.code) +// { +// case BOOL: +// case INT: +// case REAL: +// ret = true; +// break; +// +// default: +// ret = false; +// break; +// } +// return ret; +//} +// +//bool ast_areconst(AstNode* left, AstNode* right) +//{ +// return ast_isconst(left) && ast_isconst(right); +//} +// +//static AstNode* ast_new(int code, Type* type, AstNode* l0, AstNode* l1, AstNode* l2) +//{ +// AstNode* node = calloc(1, sizeof(AstNode)); +// node->hdr.code = code; +// node->hdr.type = type; +// node->links[0] = l0; +// node->links[1] = l1; +// node->links[2] = l2; +// return node; +//} +// +//static AstNode* ast_clone(AstNode* parent) +//{ +// AstNode* node = calloc(1, sizeof(AstNode)); +// *node = *parent; +// return node; +//} +// +//AstNode* ast_ident(Parser* p, long long index) +//{ +// Symbol* sym = symbol_getbyid(p, (size_t)index); +// AstNode* node; +// if (sym && sym->class == SYM_CONST) +// { +// assert(sym->value != NULL); +// node = ast_clone(sym->value); +// } +// else +// { +// node = ast_new(IDENT, sym->type, NULL, NULL, NULL); +// ((AstValue*)node)->val.i = index; +// } +// return (AstNode*)node; +//} +// +//AstNode* ast_bool(Parser* p, bool val) +//{ +// (void)p; +// AstValue* node = (AstValue*)ast_new(BOOL, &BoolType, NULL, NULL, NULL); +// node->val.i = val; +// return (AstNode*)node; +//} +// +//AstNode* ast_int(Parser* p, long long val) +//{ +// (void)p; +// AstValue* node = (AstValue*)ast_new(INT, &IntType, NULL, NULL, NULL); +// node->val.i = val; +// return (AstNode*)node; +//} +// +//AstNode* ast_real(Parser* p, double val) +//{ +// (void)p; +// AstValue* node = (AstValue*)ast_new(REAL, &RealType, NULL, NULL, NULL); +// node->val.f = val; +// return (AstNode*)node; +//} +// +//bool ast_asbool(AstNode* node) +//{ +// assert(node->hdr.type->form == FORM_BOOL); +// return (bool)(((AstValue*)node)->val.i); +//} +// +//long long ast_asint(AstNode* node) +//{ +// assert(node->hdr.type->form == FORM_INT); +// return ((AstValue*)node)->val.i; +//} +// +//double ast_asreal(AstNode* node) +//{ +// assert(node->hdr.type->form == FORM_REAL); +// return ((AstValue*)node)->val.f; +//} +// +//static AstNode* ast_binop(int op, AstNode* left, AstNode* right) +//{ +// assert(left); +// assert(right); +// AstNode* ret = NULL; +// if (ast_areconst(left,right)) +// { +// AstValue* a = (AstValue*)left; +// AstValue* b = (AstValue*)right; +// if (a->hdr.type->form == FORM_INT || a->hdr.type->form == FORM_BOOL) +// { +// switch (op) +// { +// case '+': a->val.i = a->val.i + b->val.i; break; +// case '-': a->val.i = a->val.i - b->val.i; break; +// case '*': a->val.i = a->val.i * b->val.i; break; +// case '/': a->val.i = a->val.i / b->val.i; break; +// case '%': a->val.i = a->val.i % b->val.i; break; +// case AND: a->val.i = a->val.i && b->val.i; break; +// case OR: a->val.i = a->val.i || b->val.i; break; +// +// case EQ: +// a->val.i = a->val.i == b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// case NEQ: +// a->val.i = a->val.i != b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// case '<': +// a->val.i = a->val.i < b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// case LTEQ: +// a->val.i = a->val.i <= b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// case '>': +// a->val.i = a->val.i > b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// case GTEQ: +// a->val.i = a->val.i >= b->val.i; +// a->hdr.type = &BoolType; +// break; +// +// default: +// assert(!"not a valid op"); +// break; +// } +// } +// else if (a->hdr.type->form == FORM_REAL) +// { +// switch (op) +// { +// case '+': a->val.f = a->val.f + b->val.f; break; +// case '-': a->val.f = a->val.f - b->val.f; break; +// case '*': a->val.f = a->val.f * b->val.f; break; +// case '/': a->val.f = a->val.f / b->val.f; break; +// +// case EQ: +// a->val.f = a->val.f == b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// case NEQ: +// a->val.f = a->val.f != b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// case '<': +// a->val.f = a->val.f < b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// case LTEQ: +// a->val.f = a->val.f <= b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// case '>': +// a->val.f = a->val.f > b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// case GTEQ: +// a->val.f = a->val.f >= b->val.f; +// a->hdr.type = &BoolType; +// break; +// +// default: +// assert(!"not a valid op"); +// break; +// } +// } +// else +// { +// assert(!"not a valid form"); +// } +// ret = (AstNode*)a; +// } +// else +// { +// switch (op) +// { +// case EQ: +// case NEQ: +// case '<': +// case LTEQ: +// case '>': +// case GTEQ: +// ret = ast_new(op, &BoolType, left, right, NULL); +// break; +// +// default: +// ret = ast_new(op, left->hdr.type, left, right, NULL); +// break; +// } +// } +// return ret; +//} +// +//static AstNode* ast_unop(int op, AstNode* operand) +//{ +// assert(operand); +// AstNode* ret = NULL; +// if (ast_isconst(operand)) +// { +// AstValue* a = (AstValue*)operand; +// if (a->hdr.type->form == FORM_INT) +// { +// switch (op) +// { +// case '+': a->val.i = +a->val.i; break; +// case '-': a->val.i = -a->val.i; break; +// default: assert(!"not a valid op"); break; +// } +// } +// else if (a->hdr.type->form == FORM_REAL) +// { +// switch (op) +// { +// case '+': a->val.f = +a->val.f; break; +// case '-': a->val.f = -a->val.f; break; +// default: assert(!"not a valid op"); break; +// } +// } +// else if (a->hdr.type->form == FORM_BOOL) +// { +// switch (op) +// { +// case NOT: a->val.i = !a->val.i; break; +// default: assert(!"not a valid op"); break; +// } +// } +// else +// { +// assert(!"not a valid form"); +// } +// ret = (AstNode*)a; +// } +// else +// { +// ret = ast_new(op, operand->hdr.type, operand, NULL, NULL); +// } +// return ret; +//} +// +//AstNode* ast_op(Parser* p, int op, AstNode* left, AstNode* right) +//{ +// (void)p; +// return (right +// ? ast_binop(op, left, right) +// : ast_unop(op, left)); +//} +// +//AstNode* ast_store(AstNode* dest, AstNode* value) +//{ +// /* TODO: validate left-hand side is assignable */ +// return ast_new('=', &VoidType, dest, value, NULL); +//} +// +//static Field* get_field(Parser* p, Type* type, char* name) +//{ +// Field* curr = type->fields; +// while (curr) +// { +// if (curr->name && !strcmp(curr->name, name)) +// { +// break; +// } +// curr = curr->next; +// } +// if (!curr) +// { +// error(p, "record has no such field '%s'\n", name); +// } +// return curr; +//} +// +//AstNode* ast_fieldref(Parser* p, AstNode* record, char* fname) +//{ +// Field* field = get_field(p, record->hdr.type, fname); +// AstNode* offset = ast_int(p, field->offset); +// if (record->hdr.code == '.') +// { +// /* accumulate the offset into an existing record access */ +// record->links[1] = ast_binop('+', record->links[1], offset); +// record->hdr.type = field->type; +// } +// else +// { +// /* create a new record access node */ +// record = ast_new('.', field->type, record, offset, NULL); +// } +// return record; +//} +// +//AstNode* ast_index(Parser* p, AstNode* array, AstNode* index) +//{ +// if (ast_isconst(index) && ast_asint(index) >= array->hdr.type->size) +// { +// error(p, "constant array index out of bounds"); +// } +// return ast_new('[', array->hdr.type->base, array, index, NULL); +//} +// +//AstNode* ast_block(void) +//{ +// return ast_new(BEGIN, &VoidType, NULL, NULL, NULL); +//} +// +//static void append(AstNode* node, int offset, AstNode* first, AstNode* last) +//{ +// if (!node->links[offset + 0]) +// { +// node->links[offset + 0] = first; +// node->links[offset + 1] = last; +// } +// else +// { +// node->links[offset + 1]->hdr.next = first; +// node->links[offset + 1] = last; +// } +//} +// +//void ast_block_add(AstNode* blk, AstNode* stmt) +//{ +// assert(blk->hdr.code == BEGIN); +// /* if we recieve a BEGIN block, we faltten it into the block by +// appending all its statemtents */ +// if (stmt->hdr.code == BEGIN) +// { +// append(blk, 0, stmt->links[0], stmt->links[1]); +// } +// /* otherwise just append the statement to the block */ +// else +// { +// append(blk, 0, stmt, stmt); +// } +//} +// +//AstNode* ast_call(AstNode* func) +//{ +// return ast_new(CALL, func->hdr.type, func, NULL, NULL); +//} +// +//void ast_call_add(AstNode* func, AstNode* arg) +//{ +// append(func, 1, arg, arg); +//} +// +//AstNode* ast_if(AstNode* cond, AstNode* br1, AstNode* br2) +//{ +// AstNode* ret; +// if (ast_isconst(cond)) +// { +// ret = (ast_asbool(cond) ? br1 : br2); +// } +// else +// { +// ret = ast_new(IF, &VoidType, cond, br1, br2); +// } +// return ret; +//} +// +//AstNode* ast_return(AstNode* expr) +//{ +// return ast_new(RETURN, &VoidType, expr, NULL, NULL); +//} +// +//static void print_indent(int indent, char* str) +//{ +// /* print the indent */ +// for (int i = 0; i < indent; i++) +// { +// printf(" "); +// } +// if (str) +// { +// printf("%s", str); +// } +//} +// +//static void print_opcode(AstNode* node) +//{ +// int op = node->hdr.code; +// if (op < 256) +// { +// printf("(%c\n", op); +// } +// else if (op == RETURN) +// { +// printf("(return\n"); +// } +// else if (op == IF) +// { +// printf("(if\n"); +// } +// else +// { +// printf("(%d\n", op); +// } +//} +// +//static void print(Parser* p, AstNode* node, int indent) +//{ +// assert(node); +// print_indent(indent, NULL); +// +// /* now print the data */ +// switch(node->hdr.code) +// { +// case BOOL: +// printf("B:%lld", ((AstValue*)node)->val.i); +// break; +// +// case INT: +// printf("I:%lld", ((AstValue*)node)->val.i); +// break; +// +// case REAL: +// printf("R:%f", ((AstValue*)node)->val.f); +// break; +// +// case IDENT: +// { +// Symbol* s = symbol_getbyid(p, ((AstValue*)node)->val.i); +// printf("%s.%lld", s->name, ((AstValue*)node)->tag); +// } +// break; +// +// case '.': +// printf("(field-ref\n"); +// print(p, node->links[0], indent+1); +// print(p, node->links[1], indent+1); +// print_indent(indent, ")"); +// break; +// +// case '[': +// printf("(array-index\n"); +// print(p, node->links[0], indent+1); +// print(p, node->links[1], indent+1); +// print_indent(indent, ")"); +// break; +// +// case BEGIN: +// printf("(begin\n"); +// for (AstNode* curr = node->links[0]; curr; curr = curr->hdr.next) +// { +// print(p, curr, indent+1); +// } +// print_indent(indent, ")"); +// break; +// +// case CALL: +// printf("(call\n"); +// print(p, node->links[0], indent+1); +// for (AstNode* curr = node->links[1]; curr; curr = curr->hdr.next) +// { +// print(p, curr, indent+1); +// } +// print_indent(indent, ")"); +// break; +// +// case IF: +// printf("(if\n"); +// print(p, node->links[0], indent+1); +// print(p, node->links[1], indent+1); +// if (node->links[2]) +// { +// print(p, node->links[2], indent+1); +// } +// print_indent(indent, ")"); +// break; +// +// default: +// if (node->links[1]) +// { +// print_opcode(node); +// print(p, node->links[0], indent+1); +// print(p, node->links[1], indent+1); +// print_indent(indent, ")"); +// } +// else +// { +// print_opcode(node); +// print(p, node->links[0], indent+1); +// print_indent(indent, ")"); +// } +// break; +// } +// puts(""); +//} +// +//void ast_print(Parser* p, AstNode* node) +//{ +// print(p, node, 0); +//} diff --git a/cerise/src/grammar.c b/cerise/src/grammar.c index 29cdc21..b737629 100644 --- a/cerise/src/grammar.c +++ b/cerise/src/grammar.c @@ -483,7 +483,7 @@ static void const_decl(Parser* p) expect(p, '='); sym->value = expression(p); sym->type = sym->value->type; - printf("%p\n", sym->value); + ssa_print(p, sym->value); } while (matches(p, IDENT)); diff --git a/cerise/src/ssa.c b/cerise/src/ssa.c index 0884cd3..9e3bbfd 100644 --- a/cerise/src/ssa.c +++ b/cerise/src/ssa.c @@ -3,8 +3,8 @@ static SsaNode* ssa_node(int code, int mode); static SsaNode* binop(Parser* p, int op, SsaNode* left, SsaNode* right); static SsaNode* unop(Parser* p, int op, SsaNode* operand); -static SsaNode* const_binop(Parser* p, int op, SsaNode* left, SsaNode* right); -static SsaNode* const_unop(Parser* p, int op, SsaNode* operand); +static SsaNode* const_binop(int op, SsaNode* left, SsaNode* right); +static SsaNode* const_unop(int op, SsaNode* operand); static SsaNode* load(Parser* p, SsaNode* node); bool ssa_asbool(SsaNode* node) @@ -16,13 +16,13 @@ bool ssa_asbool(SsaNode* node) long long ssa_asint(SsaNode* node) { assert(node->code == INT); - return (bool)(node->left.val.i); + return (node->left.val.i); } double ssa_asreal(SsaNode* node) { assert(node->code == REAL); - return (bool)(node->left.val.f); + return (node->left.val.f); } static SsaNode* ssa_node(int code, int mode) @@ -37,10 +37,20 @@ static SsaNode* ssa_node(int code, int mode) SsaNode* ssa_ident(Parser* p, long long index) { + SsaNode* node; Symbol* sym = symbol_getbyid(p, index); - SsaNode* node = ssa_node(IDENT, MODE_VAR); - node->left.var.symid = index; - node->left.var.symver = sym->version; + if (sym->class == SYM_CONST) + { + assert(sym->value != NULL); + node = calloc(1, sizeof(SsaNode)); + *node = *(sym->value); + } + else + { + node = ssa_node(IDENT, MODE_VAR); + node->left.var.symid = index; + node->left.var.symver = sym->version; + } return node; } @@ -88,6 +98,7 @@ SsaNode* ssa_store(Parser* p, SsaNode* dest, SsaNode* value) SsaNode* ssa_fieldref(Parser* p, SsaNode* record, char* fname) { + (void)p, (void)record, (void)fname; assert("!record field references unimplemented"); return NULL; } @@ -150,7 +161,7 @@ static SsaNode* binop(Parser* p, int op, SsaNode* left, SsaNode* right) SsaNode* node = NULL; if (left->mode == MODE_CONST && right->mode == MODE_CONST) { - node = const_binop(p, op, left, right); + node = const_binop(op, left, right); } else { @@ -169,7 +180,7 @@ static SsaNode* unop(Parser* p, int op, SsaNode* operand) SsaNode* node = NULL; if (operand->mode == MODE_CONST) { - node = const_unop(p, op, operand); + node = const_unop(op, operand); } else { @@ -181,18 +192,140 @@ static SsaNode* unop(Parser* p, int op, SsaNode* operand) return node; } -static SsaNode* const_binop(Parser* p, int op, SsaNode* left, SsaNode* right) +static SsaNode* const_binop(int op, SsaNode* a, SsaNode* b) { - (void)p, (void)op, (void)left, (void)right; - /* perform the operation based on type and operator */ - return NULL; + if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) + { + switch (op) + { + case '+': a->left.val.i = a->left.val.i + b->left.val.i; break; + case '-': a->left.val.i = a->left.val.i - b->left.val.i; break; + case '*': a->left.val.i = a->left.val.i * b->left.val.i; break; + case '/': a->left.val.i = a->left.val.i / b->left.val.i; break; + case '%': a->left.val.i = a->left.val.i % b->left.val.i; break; + case AND: a->left.val.i = a->left.val.i && b->left.val.i; break; + case OR: a->left.val.i = a->left.val.i || b->left.val.i; break; + + case EQ: + a->left.val.i = a->left.val.i == b->left.val.i; + a->type = &BoolType; + break; + + case NEQ: + a->left.val.i = a->left.val.i != b->left.val.i; + a->type = &BoolType; + break; + + case '<': + a->left.val.i = a->left.val.i < b->left.val.i; + a->type = &BoolType; + break; + + case LTEQ: + a->left.val.i = a->left.val.i <= b->left.val.i; + a->type = &BoolType; + break; + + case '>': + a->left.val.i = a->left.val.i > b->left.val.i; + a->type = &BoolType; + break; + + case GTEQ: + a->left.val.i = a->left.val.i >= b->left.val.i; + a->type = &BoolType; + break; + + default: + assert(!"not a left.valid op"); + break; + } + } + else if (a->type->form == FORM_REAL) + { + switch (op) + { + case '+': a->left.val.f = a->left.val.f + b->left.val.f; break; + case '-': a->left.val.f = a->left.val.f - b->left.val.f; break; + case '*': a->left.val.f = a->left.val.f * b->left.val.f; break; + case '/': a->left.val.f = a->left.val.f / b->left.val.f; break; + + case EQ: + a->left.val.f = a->left.val.f == b->left.val.f; + a->type = &BoolType; + break; + + case NEQ: + a->left.val.f = a->left.val.f != b->left.val.f; + a->type = &BoolType; + break; + + case '<': + a->left.val.f = a->left.val.f < b->left.val.f; + a->type = &BoolType; + break; + + case LTEQ: + a->left.val.f = a->left.val.f <= b->left.val.f; + a->type = &BoolType; + break; + + case '>': + a->left.val.f = a->left.val.f > b->left.val.f; + a->type = &BoolType; + break; + + case GTEQ: + a->left.val.f = a->left.val.f >= b->left.val.f; + a->type = &BoolType; + break; + + default: + assert(!"not a left.valid op"); + break; + } + } + else + { + assert(!"not a left.valid form"); + } + return a; } -static SsaNode* const_unop(Parser* p, int op, SsaNode* operand) +static SsaNode* const_unop(int op, SsaNode* a) { - (void)p, (void)op, (void)operand; - /* perform the operation based on type and operator */ - return NULL; + if (a->type->form == FORM_INT) + { + switch (op) + { + case '+': a->left.val.i = +a->left.val.i; break; + case '-': a->left.val.i = -a->left.val.i; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_REAL) + { + switch (op) + { + case '+': a->left.val.f = +a->left.val.f; break; + case '-': a->left.val.f = -a->left.val.f; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_BOOL) + { + switch (op) + { + case NOT: a->left.val.i = !a->left.val.i; break; + default: assert(!"not a valid op"); break; + } + } + else + { + assert(!"not a valid form"); + } + + return a; } static SsaNode* load(Parser* p, SsaNode* node) @@ -350,11 +483,26 @@ static SsaNode* load(Parser* p, SsaNode* node) //{ // print(p, node, 0); //} -// + void ssa_print(Parser* p, SsaNode* expr) { -// switch (expr->code) -// { -// case -// } + (void)p; + switch(expr->code) + { + case BOOL: + printf("(Bool)%d\n", ssa_asbool(expr)); + break; + + case INT: + printf("(Int)%lld\n", ssa_asint(expr)); + break; + + case REAL: + printf("(Real)%f\n", ssa_asreal(expr)); + break; + + default: + printf("???\n"); + break; + } } diff --git a/cerise/tests/Module.m b/cerise/tests/Module.m index 995f67b..d6e2e4f 100644 --- a/cerise/tests/Module.m +++ b/cerise/tests/Module.m @@ -9,10 +9,10 @@ const B* = 42 C* = 42.0 D = -B -# E = -C -# F = not A -# G = B + 2 - 2 * 2 -# H = false or A + E = -C + F = not A + G = B + 2 - 2 * 2 + H = false or A #type # TypeA* = Int -- 2.49.0