aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2022-04-25 10:46:15 -0300
committerBad Diode <bd@badd10de.dev>2022-04-25 10:46:15 -0300
commit46c86de715afcf15af6dc4532969d0736a3a2e48 (patch)
tree7a37685636a83d13c30d4595d4bfedcc6edc0c0f
parentd30601a02fe1af1eb43f15eabf6a427baedfce14 (diff)
downloadbdl-46c86de715afcf15af6dc4532969d0736a3a2e48.tar.gz
bdl-46c86de715afcf15af6dc4532969d0736a3a2e48.zip
Add BASM generation for numeric comparisons
-rw-r--r--src/ir.c149
-rw-r--r--src/viz.c5
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 {
48} OperandType; 48} OperandType;
49 49
50static size_t reg_gen_id = 0; 50static size_t reg_gen_id = 0;
51static size_t lab_gen_id = 0;
51 52
52#define NEW_REG() (Operand){ .type = OP_TYPE_REG, .id = reg_gen_id++ } 53#define NEW_REG() (Operand){ .type = OP_TYPE_REG, .id = reg_gen_id++ }
54#define NEW_LAB() (Operand){ .type = OP_TYPE_LABEL, .id = lab_gen_id++ }
53#define NEW_S64(C) (Operand){ .type = OP_TYPE_CONST, .constant.sval = (C) } 55#define NEW_S64(C) (Operand){ .type = OP_TYPE_CONST, .constant.sval = (C) }
56#define EMIT_0(PROGRAM, LINE, OP, DST) do { \
57 Instruction inst = (Instruction){ \
58 .op = (OP), \
59 .dst = (DST), \
60 }; \
61 array_push((PROGRAM)->inst, inst); \
62 array_push((PROGRAM)->lines, (LINE)); \
63 } while(false);
64#define EMIT_1(PROGRAM, LINE, OP, DST, A) do { \
65 Instruction inst = (Instruction){ \
66 .op = (OP), \
67 .dst = (DST), \
68 .src_a = (A), \
69 }; \
70 array_push((PROGRAM)->inst, inst); \
71 array_push((PROGRAM)->lines, (LINE)); \
72 } while(false);
73#define EMIT_2(PROGRAM, LINE, OP, DST, A, B) do { \
74 Instruction inst = (Instruction){ \
75 .op = (OP), \
76 .dst = (DST), \
77 .src_a = (A), \
78 .src_b = (B), \
79 }; \
80 array_push((PROGRAM)->inst, inst); \
81 array_push((PROGRAM)->lines, (LINE)); \
82 } while(false);
54 83
55typedef struct Operand { 84typedef struct Operand {
56 OperandType type; 85 OperandType type;
@@ -85,52 +114,86 @@ typedef struct ProgramBASM {
85 LineInfo *lines; 114 LineInfo *lines;
86} ProgramBASM; 115} ProgramBASM;
87 116
117Operand emit_basm(ProgramBASM *program, Node *node);
118
119Operand
120emit_arith(ProgramBASM *program, Node *node, Operator op) {
121 LineInfo line = (LineInfo){
122 .line = node->line,
123 .col = node->col,
124 };
125 Operand reg_a = emit_basm(program, node->builtin.args[0]);
126 Operand reg_b;
127 for (size_t i = 1; i < array_size(node->builtin.args); ++i) {
128 Node *arg = node->builtin.args[i];
129 Operand reg_dst = NEW_REG();
130 reg_b = emit_basm(program, arg);
131 EMIT_2(program, line, op, reg_dst, reg_a, reg_b);
132 reg_a = reg_dst;
133 }
134 return reg_a;
135}
136
137Operand
138emit_numcomp(ProgramBASM *program, Node *node, Operator op) {
139 LineInfo line = (LineInfo){
140 .line = node->line,
141 .col = node->col,
142 };
143 Operand label_false = NEW_LAB();
144 Operand label_end = NEW_LAB();
145 Operand reg_a = emit_basm(program, node->builtin.args[0]);
146 Operand reg_b;
147 for (size_t i = 1; i < array_size(node->builtin.args); ++i) {
148 Node *arg = node->builtin.args[i];
149 reg_b = emit_basm(program, arg);
150 EMIT_2(program, line, op, label_false, reg_a, reg_b);
151 reg_a = reg_b;
152 }
153 Operand reg_out = NEW_REG();
154 EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(1));
155 EMIT_0(program, line, OP_JMP, label_end);
156 EMIT_0(program, line, OP_LABEL, label_false);
157 EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(0));
158 EMIT_0(program, line, OP_LABEL, label_end);
159 return reg_out;
160}
161
162Operand
163emit_builtin(ProgramBASM *program, Node *node) {
164 switch (node->builtin.type) {
165 case TOKEN_ADD: { return emit_arith(program, node, OP_ADD); } break;
166 case TOKEN_SUB: { return emit_arith(program, node, OP_SUB); } break;
167 case TOKEN_MUL: { return emit_arith(program, node, OP_MUL); } break;
168 case TOKEN_DIV: { return emit_arith(program, node, OP_DIV); } break;
169 case TOKEN_MOD: { return emit_arith(program, node, OP_MOD); } break;
170 case TOKEN_EQ: { return emit_numcomp(program, node, OP_JMP_NEQ); } break;
171 case TOKEN_LT: { return emit_numcomp(program, node, OP_JMP_GE); } break;
172 case TOKEN_GT: { return emit_numcomp(program, node, OP_JMP_LE); } break;
173 case TOKEN_LE: { return emit_numcomp(program, node, OP_JMP_GT); } break;
174 case TOKEN_GE: { return emit_numcomp(program, node, OP_JMP_LT); } break;
175 default: {
176 // TODO: assert unreachable.
177 return (Operand){0};
178 } break;
179 }
180}
181
182Operand
183emit_number(ProgramBASM *program, Node *node) {
184 // TODO: ldX depending on type of number.
185 LineInfo line = (LineInfo){.line = node->line, .col = node->col};
186 Operand reg_dst = NEW_REG();
187 Operand num = NEW_S64(node->number.integral);
188 EMIT_1(program, line, OP_LD64, reg_dst, num);
189 return reg_dst;
190}
191
88Operand 192Operand
89emit_basm(ProgramBASM *program, Node *node) { 193emit_basm(ProgramBASM *program, Node *node) {
90 switch (node->type) { 194 switch (node->type) {
91 case NODE_NUMBER: { 195 case NODE_NUMBER: { return emit_number(program, node); } break;
92 // TODO: ldX depending on type of number. 196 case NODE_BUILTIN: { return emit_builtin(program, node); } break;
93 Instruction inst = (Instruction){
94 .op = OP_LD64,
95 .dst = NEW_REG(),
96 .src_a = NEW_S64(node->number.integral),
97 };
98 LineInfo line = (LineInfo){.line = node->line, .col = node->col};
99 array_push(program->inst, inst);
100 array_push(program->lines, line);
101 return inst.dst;
102 } break;
103 case NODE_BUILTIN: {
104 Operator op;
105 switch (node->builtin.type) {
106 case TOKEN_ADD: { op = OP_ADD; } break;
107 case TOKEN_SUB: { op = OP_SUB; } break;
108 case TOKEN_MUL: { op = OP_MUL; } break;
109 case TOKEN_DIV: { op = OP_DIV; } break;
110 case TOKEN_MOD: { op = OP_MOD; } break;
111 default: break;
112 }
113 Operand reg_a = emit_basm(program, node->builtin.args[0]);
114 Operand reg_b;
115 for (size_t i = 1; i < array_size(node->builtin.args); ++i) {
116 Node *arg = node->builtin.args[i];
117 reg_b = emit_basm(program, arg);
118 Instruction inst = (Instruction){
119 .op = op,
120 .dst = NEW_REG(),
121 .src_a = reg_a,
122 .src_b = reg_b,
123 };
124 reg_a = inst.dst;
125 LineInfo line = (LineInfo){
126 .line = node->line,
127 .col = node->col,
128 };
129 array_push(program->inst, inst);
130 array_push(program->lines, line);
131 }
132 return reg_a;
133 } break;
134 default: { 197 default: {
135 printf("UNIMPLEMENTED\n"); 198 printf("UNIMPLEMENTED\n");
136 return (Operand){0}; 199 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) {
309 viz_operand(inst->src_b); 309 viz_operand(inst->src_b);
310 } 310 }
311 } break; 311 } break;
312 case OP_JMP:
313 case OP_LABEL: {
314 printf(" ");
315 viz_operand(inst->dst);
316 } break;
312 default: { 317 default: {
313 printf(" "); 318 printf(" ");
314 viz_operand(inst->dst); 319 viz_operand(inst->dst);