diff options
author | Bad Diode <bd@badd10de.dev> | 2022-04-25 10:46:15 -0300 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2022-04-25 10:46:15 -0300 |
commit | 46c86de715afcf15af6dc4532969d0736a3a2e48 (patch) | |
tree | 7a37685636a83d13c30d4595d4bfedcc6edc0c0f /src | |
parent | d30601a02fe1af1eb43f15eabf6a427baedfce14 (diff) | |
download | bdl-46c86de715afcf15af6dc4532969d0736a3a2e48.tar.gz bdl-46c86de715afcf15af6dc4532969d0736a3a2e48.zip |
Add BASM generation for numeric comparisons
Diffstat (limited to 'src')
-rw-r--r-- | src/ir.c | 149 | ||||
-rw-r--r-- | src/viz.c | 5 |
2 files changed, 111 insertions, 43 deletions
@@ -48,9 +48,38 @@ typedef enum OperandType { | |||
48 | } OperandType; | 48 | } OperandType; |
49 | 49 | ||
50 | static size_t reg_gen_id = 0; | 50 | static size_t reg_gen_id = 0; |
51 | static 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 | ||
55 | typedef struct Operand { | 84 | typedef 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 | ||
117 | Operand emit_basm(ProgramBASM *program, Node *node); | ||
118 | |||
119 | Operand | ||
120 | emit_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 | |||
137 | Operand | ||
138 | emit_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 | |||
162 | Operand | ||
163 | emit_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 | |||
182 | Operand | ||
183 | emit_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 | |||
88 | Operand | 192 | Operand |
89 | emit_basm(ProgramBASM *program, Node *node) { | 193 | emit_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}; |
@@ -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); |