diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-22 13:34:23 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-22 13:34:23 +0100 |
commit | 316550e9bef1afbebefd5438093b94eec4a0ecdd (patch) | |
tree | 7572ab63fe2bfa8c67a5f0202d396202c0000710 /bxgen.c | |
parent | 09e6e123d803c7587464e29532dc61a025f517d5 (diff) | |
download | bxgen-316550e9bef1afbebefd5438093b94eec4a0ecdd.zip |
Add subtraction op
Diffstat (limited to 'bxgen.c')
-rwxr-xr-x | bxgen.c | 298 |
1 files changed, 253 insertions, 45 deletions
@@ -235,6 +235,7 @@ enum { DATA_F32, DATA_F64, DATA_ADD, + DATA_SUB, DATA_REFERENCE, CTRL_CALL, CTRL_RET, @@ -370,6 +371,7 @@ typedef struct { Ret ret; Call call; Var add[2]; + Var sub[2]; }; } Node; @@ -541,6 +543,7 @@ i64 node_data_ptr(Pool *pool, u64 address); i64 node_data_i32(Pool *pool, i32 value); i64 node_data_i64(Pool *pool, i64 value); i64 node_data_add(Pool *pool, Var x, Var y); +i64 node_data_sub(Pool *pool, Var x, Var y); i64 node_ctrl_call(Pool *pool, i64 target_proc, i64 num_args, Var *args); i64 node_ctrl_call_by_name(Pool *pool, i64 name_size, c8 *name, i64 num_args, Var *args); i64 node_ctrl_ret(Pool *pool, i64 num_values, Var *values); @@ -585,6 +588,7 @@ i64 n_i64(i64 proc, i64 value); i64 n_call(i64 proc, i64 target_proc, i64 num_args, Var *args); i64 n_call_by_name(i64 proc, c8 *name, i64 num_args, Var *args); i64 n_add(i64 proc, Var x, Var y); +i64 n_sub(i64 proc, Var x, Var y); i64 n_ret(i64 proc, i64 num_vals, Var *vals); i64 p_new(i64 unit, c8 *name); @@ -896,6 +900,16 @@ i64 node_data_add(Pool *pool, Var x, Var y) { }); } +i64 node_data_sub(Pool *pool, Var x, Var y) { + return node_init(pool, (Node) { + .op = DATA_SUB, + .sub = { + x, + y, + }, + }); +} + u16 resolve_calling_convention(Pool *pool, i64 proc) { CHECK(pool != NULL, "Invalid arguments", 0); CHECK(proc != UNDEFINED, "Invalid arguments", 9); @@ -2027,7 +2041,8 @@ void x86_64_emit_node( codegen->offset_code += 5; } break; - case DATA_ADD: { + case DATA_ADD: + case DATA_SUB: { i64 src_reg = codegen->entities[n->add[0]].reg; switch (src_reg) { @@ -2571,6 +2586,177 @@ void x86_64_emit_node( proc->occupied_reg |= 1 << (dst_reg - 1); } break; + case DATA_SUB: { + // NOTE Assuming static single-assignment form. + + CHECK_NODE_(n->sub[0]); + CHECK_NODE_(n->sub[1]); + + Node *x = &pool->entities[n->sub[0]].node; + Node *y = &pool->entities[n->sub[1]].node; + + i64 dst_reg = 1; + while (dst_reg <= 4 && ((1 << (dst_reg - 1)) & proc->occupied_reg) != 0) + ++dst_reg; + + switch (dst_reg) { + case 1: { + // eax + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xb8, begin, end); // mov eax + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: + case DATA_SUB: { + FAIL("Not implemented",); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x2d, begin, end); // sub eax + write_u32(LE, y->lit.as_u32[0], begin + 1, end); + + codegen->offset_code += 5; + } break; + + case DATA_ADD: + case DATA_SUB: { + FAIL("Not implemented",); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 2: { + // ebx + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xbb, begin, end); // mov ebx + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: + case DATA_SUB: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xc3, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xcb, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + // edx + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xd3, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + case 5: + // esi + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xf3, begin + 1, end); // esi + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x81, begin, end); // sub ebx + write_u8 (LE, 0xeb, begin + 1, end); + write_u32(LE, y->lit.as_u32[0], begin + 2, end); + + codegen->offset_code += 6; + } break; + + case DATA_ADD: + case DATA_SUB: { + FAIL("Not implemented",); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 3: { + FAIL("Not implemented",); + // ecx + } break; + + case 4: { + FAIL("Not implemented",); + // edx + } break; + + case 5: { + FAIL("Not implemented",); + // esi + } break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[node].reg = dst_reg; + proc->occupied_reg |= 1 << (dst_reg - 1); + } break; + case CTRL_CALL: { CHECK(n->call.convention == CONV_CDECL, "Not implemented",); CHECK(n->call.target_proc == UNDEFINED, "Not implemented",); @@ -2853,19 +3039,20 @@ void x86_64_emit_node( case DATA_I64: { CHECK(val->lit.num_bytes == 8, "Not implemented",); - write_u8 (LE, 0xb8, begin, end); // mov eax - write_u32(LE, 60, begin + 1, end); // 60 + write_u8 (LE, 0xb8, begin, end); // mov eax + write_u32(LE, 60, begin + 1, end); // 60 - write_u8 (LE, 0xbf, begin + 5, end); // mov edi - write_u32(LE, *val->lit.as_u32, begin + 6, end); // <- literal + write_u8 (LE, 0xbf, begin + 5, end); // mov edi + write_u32(LE, val->lit.as_u32[0], begin + 6, end); - write_u8 (LE, 0x0f, begin + 10, end); // syscall - write_u8 (LE, 0x05, begin + 11, end); + write_u8 (LE, 0x0f, begin + 10, end); // syscall + write_u8 (LE, 0x05, begin + 11, end); codegen->offset_code += 12; } break; - case DATA_ADD: { + case DATA_ADD: + case DATA_SUB: { switch (codegen->entities[n_val].reg) { case 1: // eax @@ -4673,7 +4860,7 @@ void dispatch_log(i32 log_level, u32 line, c8 *file, c8 *format, ...) { wait_any_input(); break; - case WARNING: + case WARNING: fprintf(stderr, "\r\x1b[43;1m\x1b[30m Warning \x1b[40;0m\x1b[37m %s " "%.*s \x1b[36m%s\x1b[34m:%d\x1b[37m\n", @@ -4684,19 +4871,19 @@ void dispatch_log(i32 log_level, u32 line, c8 *file, c8 *format, ...) { wait_any_input(); break; - case INFO: + case INFO: fprintf(stdout, "\r\x1b[42;1m\x1b[30m Info \x1b[40;0m\x1b[37m %s\n", message); break; - case VERBOSE: + case VERBOSE: fprintf(stdout, "\r\x1b[47;1m\x1b[30m Verbose \x1b[40;0m\x1b[37m %s\n", message); break; - case TRACE: + case TRACE: fprintf(stdout, "\r\x1b[45;1m\x1b[30m Trace \x1b[40;0m\x1b[37m %s " "%.*s \x1b[36m%s\x1b[34m:%d\x1b[37m\n", @@ -4907,6 +5094,12 @@ i64 n_add(i64 proc, Var x, Var y) { return n; } +i64 n_sub(i64 proc, Var x, Var y) { + i64 n = node_data_sub(&g_pool, x, y); + p_add(proc, n); + return n; +} + i64 n_ret(i64 proc, i64 num_vals, Var *vals) { i64 n = node_ctrl_ret(&g_pool, num_vals, vals); p_add(proc, n); @@ -5045,39 +5238,41 @@ c8 *l_find(c8 *name, b8 silent) { #if HELPERS -#define ADD_TEST_(name_, res_, ...) \ - b8 name_(void) { \ - i64 u = u_new(); \ - CHECK(u != UNDEFINED, "Sanity", 0); \ - \ - __VA_ARGS__ \ - \ - u_elf_x86_64(u, "test_" #name_); \ - \ - b8 success = 1; \ - \ - if (HOST_OS != OS_Linux) { \ - LOG(INFO, "Skip running the executable. Host system is not compatible."); \ - } else if (HO != LE) { \ - LOG(INFO, "Skip running the executable. Host data ordering is not compatible."); \ - } else { \ - LOG(VERBOSE, "Running the executable"); \ - \ - i32 ret; \ - \ - if (LOG_LEVEL >= VERBOSE) \ - ret = system("./test_" #name_); \ - else \ - ret = system("./test_" #name_ " >/dev/null"); \ - \ - if (WEXITSTATUS(ret) != res_) \ - success = 0; \ - } \ - \ - if (success) \ - system("rm test_" #name_); \ - \ - return success; \ +#define ADD_TEST_(name_, res_, ...) \ + b8 name_(void) { \ + i64 u = u_new(); \ + CHECK(u != UNDEFINED, "Sanity", 0); \ + \ + __VA_ARGS__ \ + \ + u_elf_x86_64(u, "test_" #name_); \ + \ + b8 success = 1; \ + \ + if (HOST_OS != OS_Linux) { \ + LOG(INFO, "Skip running the executable. " \ + "Host system is not compatible."); \ + } else if (HO != LE) { \ + LOG(INFO, "Skip running the executable. " \ + "Host data ordering is not compatible."); \ + } else { \ + LOG(VERBOSE, "Running the executable"); \ + \ + i32 ret; \ + \ + if (LOG_LEVEL >= VERBOSE) \ + ret = system("./test_" #name_); \ + else \ + ret = system("./test_" #name_ " >/dev/null"); \ + \ + if (WEXITSTATUS(ret) != res_) \ + success = 0; \ + } \ + \ + if (success) \ + system("rm test_" #name_); \ + \ + return success; \ } ADD_TEST_(link_with_libc, 42, @@ -5226,6 +5421,18 @@ ADD_TEST_(math_add_8, 1+2+3+4+5+6+7+8, ); ) +ADD_TEST_(math_sub_3, 3-2-1, + i64 mainproc = p_new_entry(u); + + i64 a = n_sub(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 2)); + i64 b = n_i32(mainproc, 1); + + N_RET( + mainproc, + n_sub(mainproc, a, b) + ); +) + #endif // HELPERS i32 main(i32 argc, c8 **argv) { @@ -5303,6 +5510,7 @@ i32 main(i32 argc, c8 **argv) { RUN_TEST_(math_add_7); RUN_TEST_(math_add_4b); RUN_TEST_(math_add_8); + RUN_TEST_(math_sub_3); #endif #undef RUN_TEST_ |