From ada3f3a2eac5b3828c3a55970d5640fef922d3d0 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Mon, 25 Apr 2022 11:59:22 -0300 Subject: Add BASM generation for `if` expressions --- src/ir.c | 45 ++++++++++++++++++++++++++++++++++---- src/ir.h | 2 ++ src/viz.c | 75 +++++++++++++++++++++++++++++++++++---------------------------- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/ir.c b/src/ir.c index f1b7eb9..86a1a9a 100644 --- a/src/ir.c +++ b/src/ir.c @@ -13,8 +13,8 @@ emit_arith(ProgramBASM *program, Node *node, Operator op) { Operand reg_b; for (size_t i = 1; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; - Operand reg_dst = NEW_REG(); reg_b = emit_basm(program, arg); + Operand reg_dst = NEW_REG(); EMIT_2(program, line, op, reg_dst, reg_a, reg_b); reg_a = reg_dst; } @@ -90,14 +90,50 @@ emit_bool(ProgramBASM *program, Node *node) { return reg_dst; } -// TODO: emit_if +Operand +emit_if(ProgramBASM *program, Node *node) { + LineInfo line = (LineInfo){.line = node->line, .col = node->col}; + Operand label_false = NEW_LAB(); + Operand label_end = NEW_LAB(); + + // If type of expression is `void`, there is nothing to return. Don't + // generate a new register or copy output. + Operand reg_out = (Operand){0}; + if (node->expr_type != &default_types[TYPE_VOID]) { + reg_out = NEW_REG(); + } + + Operand cond = emit_basm(program, node->ifexpr.cond); + EMIT_1(program, line, OP_JMP_FALSE, label_false, cond); + + Operand ret_true = emit_basm(program, node->ifexpr.expr_true); + if (node->ifexpr.expr_false != NULL) { + if (node->expr_type != &default_types[TYPE_VOID]) { + EMIT_1(program, line, OP_CP64, reg_out, ret_true); // TODO: depends on the type of output + } + EMIT_0(program, line, OP_JMP, label_end); + EMIT_0(program, line, OP_LABEL, label_false); + Operand ret_false = emit_basm(program, node->ifexpr.expr_false); + if (node->expr_type != &default_types[TYPE_VOID]) { + EMIT_1(program, line, OP_CP64, reg_out, ret_false); // TODO: depends on the type of output + } + EMIT_0(program, line, OP_LABEL, label_end); + } else { + EMIT_0(program, line, OP_LABEL, label_false); + } + + return reg_out; +} + // TODO: emit_and // TODO: emit_or // TODO: emit_not -// TODO: emit_global -// TODO: emit_local +// TODO: emit_block // TODO: emit_procedure +// TODO: emit_local_vars +// TODO: emit_param_vars // TODO: emit_proc_call +// TODO: emit_global_vars Operand emit_basm(ProgramBASM *program, Node *node) { @@ -105,6 +141,7 @@ emit_basm(ProgramBASM *program, Node *node) { case NODE_BOOL: { return emit_bool(program, node); } break; case NODE_NUMBER: { return emit_number(program, node); } break; case NODE_BUILTIN: { return emit_builtin(program, node); } break; + case NODE_IF: { return emit_if(program, node); } break; default: { push_error(ERR_TYPE_BASM, ERR_UNIMPLEMENTED, node->line, node->col); return (Operand){0}; diff --git a/src/ir.h b/src/ir.h index d5b167e..c0ce22a 100644 --- a/src/ir.h +++ b/src/ir.h @@ -36,6 +36,8 @@ typedef enum Operator { // (Un)conditional jump operations. OP_LABEL, OP_JMP, + OP_JMP_TRUE, + OP_JMP_FALSE, OP_JMP_EQ, OP_JMP_NEQ, OP_JMP_GT, diff --git a/src/viz.c b/src/viz.c index 3d6a0f7..8e31387 100644 --- a/src/viz.c +++ b/src/viz.c @@ -237,39 +237,41 @@ viz_symtables(Scope **scopes) { } static const char* basm_op_str[] = { - [OP_ADD] = "add ", - [OP_SUB] = "sub ", - [OP_MUL] = "mul ", - [OP_DIV] = "div ", - [OP_MOD] = "mod ", - [OP_LD8] = "ld8 ", - [OP_LD16] = "ld16 ", - [OP_LD32] = "ld32 ", - [OP_LD64] = "ld64 ", - [OP_ST8] = "st8 ", - [OP_ST16] = "st16 ", - [OP_ST32] = "st32 ", - [OP_ST64] = "st64 ", - [OP_CP8] = "cp8 ", - [OP_CP16] = "cp16 ", - [OP_CP32] = "cp32 ", - [OP_CP64] = "cp64 ", - [OP_NOT] = "not ", - [OP_AND] = "and ", - [OP_OR] = "or ", - [OP_XOR] = "xor ", - [OP_LSHIFT] = "lshift", - [OP_RSHIFT] = "rshift", - [OP_LROT] = "lrot ", - [OP_RROT] = "rrot ", - [OP_LABEL] = "lab ", - [OP_JMP] = "jmp ", - [OP_JMP_EQ] = "jeq ", - [OP_JMP_NEQ] = "jne ", - [OP_JMP_GT] = "jgt ", - [OP_JMP_LT] = "jlt ", - [OP_JMP_GE] = "jge ", - [OP_JMP_LE] = "jle ", + [OP_ADD] = "add ", + [OP_SUB] = "sub ", + [OP_MUL] = "mul ", + [OP_DIV] = "div ", + [OP_MOD] = "mod ", + [OP_LD8] = "ld8 ", + [OP_LD16] = "ld16 ", + [OP_LD32] = "ld32 ", + [OP_LD64] = "ld64 ", + [OP_ST8] = "st8 ", + [OP_ST16] = "st16 ", + [OP_ST32] = "st32 ", + [OP_ST64] = "st64 ", + [OP_CP8] = "cp8 ", + [OP_CP16] = "cp16 ", + [OP_CP32] = "cp32 ", + [OP_CP64] = "cp64 ", + [OP_NOT] = "not ", + [OP_AND] = "and ", + [OP_OR] = "or ", + [OP_XOR] = "xor ", + [OP_LSHIFT] = "lshift", + [OP_RSHIFT] = "rshift", + [OP_LROT] = "lrot ", + [OP_RROT] = "rrot ", + [OP_LABEL] = "lab ", + [OP_JMP] = "jmp ", + [OP_JMP_TRUE] = "jt ", + [OP_JMP_FALSE] = "jf ", + [OP_JMP_EQ] = "jeq ", + [OP_JMP_NEQ] = "jne ", + [OP_JMP_GT] = "jgt ", + [OP_JMP_LT] = "jlt ", + [OP_JMP_GE] = "jge ", + [OP_JMP_LE] = "jle ", }; void @@ -314,6 +316,13 @@ viz_instruction(Instruction *inst, LineInfo *line) { printf(" "); viz_operand(inst->dst); } break; + case OP_JMP_TRUE: + case OP_JMP_FALSE: { + printf(" "); + viz_operand(inst->dst); + printf(", "); + viz_operand(inst->src_a); + } break; default: { printf(" "); viz_operand(inst->dst); -- cgit v1.2.1