summaryrefslogtreecommitdiff
path: root/bxgen.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-11-22 13:34:23 +0100
committerMitya Selivanov <automainint@guattari.tech>2024-11-22 13:34:23 +0100
commit316550e9bef1afbebefd5438093b94eec4a0ecdd (patch)
tree7572ab63fe2bfa8c67a5f0202d396202c0000710 /bxgen.c
parent09e6e123d803c7587464e29532dc61a025f517d5 (diff)
downloadbxgen-316550e9bef1afbebefd5438093b94eec4a0ecdd.zip
Add subtraction op
Diffstat (limited to 'bxgen.c')
-rwxr-xr-xbxgen.c298
1 files changed, 253 insertions, 45 deletions
diff --git a/bxgen.c b/bxgen.c
index 98ddd30..ceca08c 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -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_