From 46c86de715afcf15af6dc4532969d0736a3a2e48 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Mon, 25 Apr 2022 10:46:15 -0300 Subject: Add BASM generation for numeric comparisons --- src/ir.c | 149 ++++++++++++++++++++++++++++++++++++++++++++------------------ src/viz.c | 5 +++ 2 files changed, 111 insertions(+), 43 deletions(-) diff --git a/src/ir.c b/src/ir.c index 4eeb07b..2b289d9 100644 --- a/src/ir.c +++ b/src/ir.c @@ -48,9 +48,38 @@ typedef enum OperandType { } OperandType; static size_t reg_gen_id = 0; +static size_t lab_gen_id = 0; #define NEW_REG() (Operand){ .type = OP_TYPE_REG, .id = reg_gen_id++ } +#define NEW_LAB() (Operand){ .type = OP_TYPE_LABEL, .id = lab_gen_id++ } #define NEW_S64(C) (Operand){ .type = OP_TYPE_CONST, .constant.sval = (C) } +#define EMIT_0(PROGRAM, LINE, OP, DST) do { \ + Instruction inst = (Instruction){ \ + .op = (OP), \ + .dst = (DST), \ + }; \ + array_push((PROGRAM)->inst, inst); \ + array_push((PROGRAM)->lines, (LINE)); \ + } while(false); +#define EMIT_1(PROGRAM, LINE, OP, DST, A) do { \ + Instruction inst = (Instruction){ \ + .op = (OP), \ + .dst = (DST), \ + .src_a = (A), \ + }; \ + array_push((PROGRAM)->inst, inst); \ + array_push((PROGRAM)->lines, (LINE)); \ + } while(false); +#define EMIT_2(PROGRAM, LINE, OP, DST, A, B) do { \ + Instruction inst = (Instruction){ \ + .op = (OP), \ + .dst = (DST), \ + .src_a = (A), \ + .src_b = (B), \ + }; \ + array_push((PROGRAM)->inst, inst); \ + array_push((PROGRAM)->lines, (LINE)); \ + } while(false); typedef struct Operand { OperandType type; @@ -85,52 +114,86 @@ typedef struct ProgramBASM { LineInfo *lines; } ProgramBASM; +Operand emit_basm(ProgramBASM *program, Node *node); + +Operand +emit_arith(ProgramBASM *program, Node *node, Operator op) { + LineInfo line = (LineInfo){ + .line = node->line, + .col = node->col, + }; + Operand reg_a = emit_basm(program, node->builtin.args[0]); + 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); + EMIT_2(program, line, op, reg_dst, reg_a, reg_b); + reg_a = reg_dst; + } + return reg_a; +} + +Operand +emit_numcomp(ProgramBASM *program, Node *node, Operator op) { + LineInfo line = (LineInfo){ + .line = node->line, + .col = node->col, + }; + Operand label_false = NEW_LAB(); + Operand label_end = NEW_LAB(); + Operand reg_a = emit_basm(program, node->builtin.args[0]); + Operand reg_b; + for (size_t i = 1; i < array_size(node->builtin.args); ++i) { + Node *arg = node->builtin.args[i]; + reg_b = emit_basm(program, arg); + EMIT_2(program, line, op, label_false, reg_a, reg_b); + reg_a = reg_b; + } + Operand reg_out = NEW_REG(); + EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(1)); + EMIT_0(program, line, OP_JMP, label_end); + EMIT_0(program, line, OP_LABEL, label_false); + EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(0)); + EMIT_0(program, line, OP_LABEL, label_end); + return reg_out; +} + +Operand +emit_builtin(ProgramBASM *program, Node *node) { + switch (node->builtin.type) { + case TOKEN_ADD: { return emit_arith(program, node, OP_ADD); } break; + case TOKEN_SUB: { return emit_arith(program, node, OP_SUB); } break; + case TOKEN_MUL: { return emit_arith(program, node, OP_MUL); } break; + case TOKEN_DIV: { return emit_arith(program, node, OP_DIV); } break; + case TOKEN_MOD: { return emit_arith(program, node, OP_MOD); } break; + case TOKEN_EQ: { return emit_numcomp(program, node, OP_JMP_NEQ); } break; + case TOKEN_LT: { return emit_numcomp(program, node, OP_JMP_GE); } break; + case TOKEN_GT: { return emit_numcomp(program, node, OP_JMP_LE); } break; + case TOKEN_LE: { return emit_numcomp(program, node, OP_JMP_GT); } break; + case TOKEN_GE: { return emit_numcomp(program, node, OP_JMP_LT); } break; + default: { + // TODO: assert unreachable. + return (Operand){0}; + } break; + } +} + +Operand +emit_number(ProgramBASM *program, Node *node) { + // TODO: ldX depending on type of number. + LineInfo line = (LineInfo){.line = node->line, .col = node->col}; + Operand reg_dst = NEW_REG(); + Operand num = NEW_S64(node->number.integral); + EMIT_1(program, line, OP_LD64, reg_dst, num); + return reg_dst; +} + Operand emit_basm(ProgramBASM *program, Node *node) { switch (node->type) { - case NODE_NUMBER: { - // TODO: ldX depending on type of number. - Instruction inst = (Instruction){ - .op = OP_LD64, - .dst = NEW_REG(), - .src_a = NEW_S64(node->number.integral), - }; - LineInfo line = (LineInfo){.line = node->line, .col = node->col}; - array_push(program->inst, inst); - array_push(program->lines, line); - return inst.dst; - } break; - case NODE_BUILTIN: { - Operator op; - switch (node->builtin.type) { - case TOKEN_ADD: { op = OP_ADD; } break; - case TOKEN_SUB: { op = OP_SUB; } break; - case TOKEN_MUL: { op = OP_MUL; } break; - case TOKEN_DIV: { op = OP_DIV; } break; - case TOKEN_MOD: { op = OP_MOD; } break; - default: break; - } - Operand reg_a = emit_basm(program, node->builtin.args[0]); - Operand reg_b; - for (size_t i = 1; i < array_size(node->builtin.args); ++i) { - Node *arg = node->builtin.args[i]; - reg_b = emit_basm(program, arg); - Instruction inst = (Instruction){ - .op = op, - .dst = NEW_REG(), - .src_a = reg_a, - .src_b = reg_b, - }; - reg_a = inst.dst; - LineInfo line = (LineInfo){ - .line = node->line, - .col = node->col, - }; - array_push(program->inst, inst); - array_push(program->lines, line); - } - return reg_a; - } break; + case NODE_NUMBER: { return emit_number(program, node); } break; + case NODE_BUILTIN: { return emit_builtin(program, node); } break; default: { printf("UNIMPLEMENTED\n"); return (Operand){0}; diff --git a/src/viz.c b/src/viz.c index eb5631b..3d6a0f7 100644 --- a/src/viz.c +++ b/src/viz.c @@ -309,6 +309,11 @@ viz_instruction(Instruction *inst, LineInfo *line) { viz_operand(inst->src_b); } } break; + case OP_JMP: + case OP_LABEL: { + printf(" "); + viz_operand(inst->dst); + } break; default: { printf(" "); viz_operand(inst->dst); -- cgit v1.2.1