diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-28 17:18:19 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-28 17:18:19 +0200 |
commit | ef1f5f9478195059828d0edeb52fa15f610f5a04 (patch) | |
tree | 5f20d045994b952050a1e5c10f80a3c4e5422f2b | |
parent | 2bf7cd7633d0040546c28462d61a1f181dd7e858 (diff) | |
download | bdl-ef1f5f9478195059828d0edeb52fa15f610f5a04.tar.gz bdl-ef1f5f9478195059828d0edeb52fa15f610f5a04.zip |
Add bitwise operations
-rw-r--r-- | src/compiler.c | 53 | ||||
-rw-r--r-- | src/vm.c | 23 | ||||
-rw-r--r-- | tests/compilation.bad | 8 |
3 files changed, 81 insertions, 3 deletions
diff --git a/src/compiler.c b/src/compiler.c index a251a90..e303cee 100644 --- a/src/compiler.c +++ b/src/compiler.c | |||
@@ -114,6 +114,17 @@ typedef enum OpCode { | |||
114 | OP_AND, // and rx, ra, rb | 114 | OP_AND, // and rx, ra, rb |
115 | OP_OR, // or rx, ra, rb | 115 | OP_OR, // or rx, ra, rb |
116 | OP_NOT, // not rx, ra | 116 | OP_NOT, // not rx, ra |
117 | // Bitwise operations. | ||
118 | OP_BITLSHIFTI, // shli rx, ra, cb | ||
119 | OP_BITRSHIFTI, // shri rx, ra, cb | ||
120 | OP_BITANDI, // bandi rx, ra, cb | ||
121 | OP_BITORI, // bori rx, ra, cb | ||
122 | OP_BITNOTI, // bnoti rx, ca | ||
123 | OP_BITLSHIFT, // shl rx, ra, rb | ||
124 | OP_BITRSHIFT, // shr rx, ra, rb | ||
125 | OP_BITAND, // band rx, ra, rb | ||
126 | OP_BITOR, // bor rx, ra, rb | ||
127 | OP_BITNOT, // bnot rx, ra | ||
117 | } OpCode; | 128 | } OpCode; |
118 | 129 | ||
119 | Str op_str[] = { | 130 | Str op_str[] = { |
@@ -185,6 +196,17 @@ Str op_str[] = { | |||
185 | [OP_AND] = cstr("AND "), | 196 | [OP_AND] = cstr("AND "), |
186 | [OP_OR] = cstr("OR "), | 197 | [OP_OR] = cstr("OR "), |
187 | [OP_NOT] = cstr("NOT "), | 198 | [OP_NOT] = cstr("NOT "), |
199 | // Bitwise operations. | ||
200 | [OP_BITLSHIFTI] = cstr("LSHI "), | ||
201 | [OP_BITRSHIFTI] = cstr("RSHI "), | ||
202 | [OP_BITANDI] = cstr("BANDI "), | ||
203 | [OP_BITORI] = cstr("BORI "), | ||
204 | [OP_BITNOTI] = cstr("BNOTI "), | ||
205 | [OP_BITLSHIFT] = cstr("LSH "), | ||
206 | [OP_BITRSHIFT] = cstr("RSH "), | ||
207 | [OP_BITAND] = cstr("BAND "), | ||
208 | [OP_BITOR] = cstr("BOR "), | ||
209 | [OP_BITNOT] = cstr("BNOT "), | ||
188 | }; | 210 | }; |
189 | 211 | ||
190 | typedef enum { | 212 | typedef enum { |
@@ -218,6 +240,7 @@ compile_binary(Chunk *chunk, Node *node) { | |||
218 | OpCode opi = OP_HALT; | 240 | OpCode opi = OP_HALT; |
219 | OpCode ldop = OP_LD64K; | 241 | OpCode ldop = OP_LD64K; |
220 | switch (node->kind) { | 242 | switch (node->kind) { |
243 | // Arithmetic. | ||
221 | case NODE_ADD: { | 244 | case NODE_ADD: { |
222 | if (str_eq(node->type, cstr("int"))) { | 245 | if (str_eq(node->type, cstr("int"))) { |
223 | op = OP_ADD; | 246 | op = OP_ADD; |
@@ -263,6 +286,7 @@ compile_binary(Chunk *chunk, Node *node) { | |||
263 | opi = OP_MODFI; | 286 | opi = OP_MODFI; |
264 | } | 287 | } |
265 | } break; | 288 | } break; |
289 | // Logic. | ||
266 | case NODE_EQ: { | 290 | case NODE_EQ: { |
267 | op = OP_EQ; | 291 | op = OP_EQ; |
268 | opi = OP_EQI; | 292 | opi = OP_EQI; |
@@ -295,6 +319,23 @@ compile_binary(Chunk *chunk, Node *node) { | |||
295 | op = OP_OR; | 319 | op = OP_OR; |
296 | opi = OP_ORI; | 320 | opi = OP_ORI; |
297 | } break; | 321 | } break; |
322 | // Bitwise. | ||
323 | case NODE_BITOR: { | ||
324 | op = OP_BITOR; | ||
325 | opi = OP_BITORI; | ||
326 | } break; | ||
327 | case NODE_BITAND: { | ||
328 | op = OP_BITAND; | ||
329 | opi = OP_BITANDI; | ||
330 | } break; | ||
331 | case NODE_BITLSHIFT: { | ||
332 | op = OP_BITLSHIFT; | ||
333 | opi = OP_BITLSHIFTI; | ||
334 | } break; | ||
335 | case NODE_BITRSHIFT: { | ||
336 | op = OP_BITRSHIFT; | ||
337 | opi = OP_BITRSHIFTI; | ||
338 | } break; | ||
298 | default: break; | 339 | default: break; |
299 | } | 340 | } |
300 | CompResult comp_a = compile_expr(chunk, node->left); | 341 | CompResult comp_a = compile_expr(chunk, node->left); |
@@ -334,12 +375,15 @@ CompResult | |||
334 | compile_unary(Chunk *chunk, Node *node) { | 375 | compile_unary(Chunk *chunk, Node *node) { |
335 | OpCode op = OP_HALT; | 376 | OpCode op = OP_HALT; |
336 | OpCode opi = OP_HALT; | 377 | OpCode opi = OP_HALT; |
337 | OpCode ldop = OP_LD64K; | ||
338 | switch (node->kind) { | 378 | switch (node->kind) { |
339 | case NODE_NOT: { | 379 | case NODE_NOT: { |
340 | op = OP_NOT; | 380 | op = OP_NOT; |
341 | opi = OP_NOTI; | 381 | opi = OP_NOTI; |
342 | } break; | 382 | } break; |
383 | case NODE_BITNOT: { | ||
384 | op = OP_BITNOT; | ||
385 | opi = OP_BITNOTI; | ||
386 | } break; | ||
343 | default: break; | 387 | default: break; |
344 | } | 388 | } |
345 | CompResult comp_a = compile_expr(chunk, node->left); | 389 | CompResult comp_a = compile_expr(chunk, node->left); |
@@ -366,6 +410,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
366 | switch (node->kind) { | 410 | switch (node->kind) { |
367 | // Logic. | 411 | // Logic. |
368 | // case NODE_XOR: | 412 | // case NODE_XOR: |
413 | case NODE_BITNOT: | ||
369 | case NODE_NOT: return compile_unary(chunk, node); break; | 414 | case NODE_NOT: return compile_unary(chunk, node); break; |
370 | case NODE_AND: | 415 | case NODE_AND: |
371 | case NODE_OR: | 416 | case NODE_OR: |
@@ -374,6 +419,11 @@ compile_expr(Chunk *chunk, Node *node) { | |||
374 | case NODE_LT: | 419 | case NODE_LT: |
375 | case NODE_GT: | 420 | case NODE_GT: |
376 | case NODE_LE: | 421 | case NODE_LE: |
422 | // Bitwise ops. | ||
423 | case NODE_BITAND: | ||
424 | case NODE_BITOR: | ||
425 | case NODE_BITLSHIFT: | ||
426 | case NODE_BITRSHIFT: | ||
377 | // Arithmetic. | 427 | // Arithmetic. |
378 | case NODE_GE: | 428 | case NODE_GE: |
379 | case NODE_ADD: | 429 | case NODE_ADD: |
@@ -384,6 +434,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
384 | case NODE_TRUE: | 434 | case NODE_TRUE: |
385 | case NODE_FALSE: | 435 | case NODE_FALSE: |
386 | case NODE_NUM_FLOAT: | 436 | case NODE_NUM_FLOAT: |
437 | case NODE_NUM_UINT: | ||
387 | case NODE_NUM_INT: { | 438 | case NODE_NUM_INT: { |
388 | sz value = node->value.i; | 439 | sz value = node->value.i; |
389 | // Make sure we don't have duplicated constants. | 440 | // Make sure we don't have duplicated constants. |
@@ -47,6 +47,10 @@ disassemble_instruction(Instruction instruction) { | |||
47 | case OP_GEI: | 47 | case OP_GEI: |
48 | case OP_ANDI: | 48 | case OP_ANDI: |
49 | case OP_ORI: | 49 | case OP_ORI: |
50 | case OP_BITLSHIFTI: | ||
51 | case OP_BITRSHIFTI: | ||
52 | case OP_BITANDI: | ||
53 | case OP_BITORI: | ||
50 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, | 54 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, |
51 | instruction.a, instruction.b); | 55 | instruction.a, instruction.b); |
52 | break; | 56 | break; |
@@ -76,13 +80,19 @@ disassemble_instruction(Instruction instruction) { | |||
76 | case OP_GE: | 80 | case OP_GE: |
77 | case OP_AND: | 81 | case OP_AND: |
78 | case OP_OR: | 82 | case OP_OR: |
83 | case OP_BITLSHIFT: | ||
84 | case OP_BITRSHIFT: | ||
85 | case OP_BITAND: | ||
86 | case OP_BITOR: | ||
79 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, | 87 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, |
80 | instruction.a, instruction.b); | 88 | instruction.a, instruction.b); |
81 | break; | 89 | break; |
90 | case OP_BITNOTI: | ||
82 | case OP_NOTI: | 91 | case OP_NOTI: |
83 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, | 92 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, |
84 | instruction.a, instruction.b); | 93 | instruction.a, instruction.b); |
85 | break; | 94 | break; |
95 | case OP_BITNOT: | ||
86 | case OP_NOT: | 96 | case OP_NOT: |
87 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | 97 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
88 | instruction.a, instruction.b); | 98 | instruction.a, instruction.b); |
@@ -183,6 +193,11 @@ vm_run(VM *vm) { | |||
183 | vm->regs[dst].i = vm->chunk->constants[src_a].i; | 193 | vm->regs[dst].i = vm->chunk->constants[src_a].i; |
184 | } break; | 194 | } break; |
185 | case OP_NOT: OP_UNARY(!, i) break; | 195 | case OP_NOT: OP_UNARY(!, i) break; |
196 | case OP_BITNOT: OP_UNARY(~, i) break; | ||
197 | case OP_BITOR: OP_BINARY(|, i) break; | ||
198 | case OP_BITAND: OP_BINARY(&, i) break; | ||
199 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; | ||
200 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; | ||
186 | case OP_EQ: OP_BINARY(==, i) break; | 201 | case OP_EQ: OP_BINARY(==, i) break; |
187 | case OP_NEQ: OP_BINARY(!=, i) break; | 202 | case OP_NEQ: OP_BINARY(!=, i) break; |
188 | case OP_LT: OP_BINARY(<, i) break; | 203 | case OP_LT: OP_BINARY(<, i) break; |
@@ -208,6 +223,11 @@ vm_run(VM *vm) { | |||
208 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | 223 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); |
209 | } break; | 224 | } break; |
210 | case OP_NOTI: OP_UNARY_CONST(!, i) break; | 225 | case OP_NOTI: OP_UNARY_CONST(!, i) break; |
226 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; | ||
227 | case OP_BITORI: OP_BINARY_CONST(|, i) break; | ||
228 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; | ||
229 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; | ||
230 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; | ||
211 | case OP_EQI: OP_BINARY_CONST(==, i) break; | 231 | case OP_EQI: OP_BINARY_CONST(==, i) break; |
212 | case OP_NEQI: OP_BINARY_CONST(!=, i) break; | 232 | case OP_NEQI: OP_BINARY_CONST(!=, i) break; |
213 | case OP_LTI: OP_BINARY_CONST(<, i) break; | 233 | case OP_LTI: OP_BINARY_CONST(<, i) break; |
@@ -233,8 +253,9 @@ vm_run(VM *vm) { | |||
233 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | 253 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); |
234 | } break; | 254 | } break; |
235 | case OP_HALT: { | 255 | case OP_HALT: { |
236 | println("VM HALT (int) -> %d", vm->regs[instruction.dst]); | 256 | println("VM HALT (int) -> %d", vm->regs[instruction.dst]); |
237 | println("VM HALT (float) -> %f", vm->regs[instruction.dst]); | 257 | println("VM HALT (float) -> %f", vm->regs[instruction.dst]); |
258 | println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); | ||
238 | return; | 259 | return; |
239 | } | 260 | } |
240 | default: { | 261 | default: { |
diff --git a/tests/compilation.bad b/tests/compilation.bad index 9c8cdbb..9042242 100644 --- a/tests/compilation.bad +++ b/tests/compilation.bad | |||
@@ -1,8 +1,14 @@ | |||
1 | ; 0xf | 0xf0 | ||
2 | ; 0xf & 0xff | ||
3 | ; 0x1 << 2 | ||
4 | ; 0x1 << 2 | ||
5 | ~0xf & 0xfff | ||
6 | ; 0xf << 4 | 0xf | ||
1 | ; 1 + 2 | 7 | ; 1 + 2 |
2 | ; 1 < 2 | 8 | ; 1 < 2 |
3 | ; !(1 == 0 || 1 <= 1) | 9 | ; !(1 == 0 || 1 <= 1) |
4 | ; 1 == 1 && 1 <= 1 | 10 | ; 1 == 1 && 1 <= 1 |
5 | !(1 * 3 >= 3 && 4 != 3 + 2) | 11 | ; !((1 * 2 * 3) * (1 * 2 * 3) >= 3 && 4 != 3 + 2) |
6 | ; 1 + 2 * 3 | 12 | ; 1 + 2 * 3 |
7 | ; 1.0 + 2.0 * 3.0 | 13 | ; 1.0 + 2.0 * 3.0 |
8 | ; true | 14 | ; true |