diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-25 08:55:39 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-25 08:55:39 +0100 |
commit | 53eed017eb1260877c15f66c2d9910f118b64d29 (patch) | |
tree | f65a3f9b3ab652069edc8b6d343d7c31df4dc559 | |
parent | c75afbdcd611668e7f239dcfb4ab3846a82c0c8c (diff) | |
download | bxgen-53eed017eb1260877c15f66c2d9910f118b64d29.zip |
Codegen refactor
-rwxr-xr-x | bxgen.c | 1858 |
1 files changed, 553 insertions, 1305 deletions
@@ -44,6 +44,7 @@ #/ - RISC-V #/ - ARM #/ - WebAssembly +#/ - Dump generated asm and binary #/ - Implicit procedure prototypes #/ - Evaluation #/ - Static single-assignment @@ -126,11 +127,13 @@ gcc \ rm $BIN exit $? # */ #endif + // ================================================================ // // Types // // ================================================================ + #ifndef TYPES_HEADER_GUARD_ #define TYPES_HEADER_GUARD_ @@ -149,11 +152,13 @@ typedef float f32; typedef double f64; #endif // TYPES_HEADER_GUARD_ + // ================================================================ // // IR data declarations // // ================================================================ + #ifndef BXGEN_HEADER_GUARD_ #define BXGEN_HEADER_GUARD_ @@ -185,18 +190,19 @@ enum { // Semantic node operations // - DATA_PTR = 0, - DATA_I8, - DATA_I16, - DATA_I32, - DATA_I64, - DATA_F32, - DATA_F64, - DATA_ADD, - DATA_SUB, - DATA_REFERENCE, - CTRL_CALL, - CTRL_RET, + OP_NONE = 0, + OP_PTR, + OP_I8, + OP_I16, + OP_I32, + OP_I64, + OP_F32, + OP_F64, + OP_ADD, + OP_SUB, + OP_ADDRESS, + OP_CALL, + OP_RET, // Calling conventions @@ -261,7 +267,7 @@ enum { // REL_ADD_INSTRUCTION_ADDRESS, - REL_ADD_RO_DATA_ADDRESS, + REL_ADD_RO_OP_ADDRESS, REL_ADD_PROC_ADDRESS, }; @@ -413,6 +419,7 @@ typedef struct { Chunk_Handle rels; Chunk_Handle output_buffer; } Linker_Context; + // ================================================================ // // API declarations @@ -426,6 +433,7 @@ typedef struct { // See: `* Helper procedures` // // ================================================================ + #ifdef __cplusplus extern "C" { #endif @@ -433,11 +441,13 @@ extern "C" { void dispatch_assert(b8 condition, c8 *message, u32 line, c8 *file); void dispatch_log(i32 log_level, u32 line, c8 *file, c8 *format, ...); void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data); + // ================================================================ // // Main API // // ================================================================ + i64 pool_add(Pool *pool, Entity data); void pool_remove(Pool *pool, i64 entity, u16 type); @@ -469,7 +479,8 @@ void unit_link_add(Pool *pool, i64 unit, i64 link_unit); void unit_link_remove(Pool *pool, i64 unit, i64 link_unit); void unit_set_name(Pool *pool, i64 unit, i64 name_size, c8 *name); void unit_set_entry_point(Pool *pool, i64 unit, i64 entry_point_proc); -void unit_write(Pool *pool, i64 unit, u16 format, u16 arch, i64 io_id, void *io_user_data); +i64 unit_write_in_memory(Pool *pool, Codegen_Context *codegen, Linker_Context *linker, i64 unit, u16 format, u16 arch); +b8 unit_write(Pool *pool, i64 unit, u16 format, u16 arch, i64 io_id, void *io_user_data); i64 io_open_read(i64 name_size, c8 *name, void *user_data); i64 io_open_write(i64 name_size, c8 *name, void *user_data); @@ -479,11 +490,13 @@ i64 io_tell(i64 f, void *user_data); i64 io_read(i64 f, i64 size, void *data, void *user_data); i64 io_write(i64 f, i64 size, void *data, void *user_data); void io_chmod_exe(i64 f, void *user_data); + // ================================================================ // // Helpers API // // ================================================================ + #ifndef DISABLE_HELPERS i64 n_ref(i64 proc, i64 node); @@ -525,6 +538,7 @@ c8 * l_find(c8 *name, b8 silent); #endif #endif // BXGEN_HEADER_GUARD_ + // ================================================================ // // IMPLEMENTATION @@ -534,6 +548,7 @@ c8 * l_find(c8 *name, b8 silent); // Compilation options // // ================================================================ + #ifndef BXGEN_HEADER #ifndef BXGEN_IMPL_GUARD_ #define BXGEN_IMPL_GUARD_ @@ -563,11 +578,13 @@ c8 * l_find(c8 *name, b8 silent); #endif #define VERSION "dev" + // ================================================================ // // * Basic utilities // // ================================================================ + #ifndef NULL #define NULL ((void *) 0) #endif @@ -619,12 +636,12 @@ c8 * l_find(c8 *name, b8 silent); } while (0) i64 align(i64 x, i64 a) { - CHECK(a > 0, "Invalid arguments", 0); + CHECK(a > 0, "Sanity", 0); return x + ((a - (x % a)) % a); } void mem_set(void *dst, u8 val, i64 size) { - CHECK(dst != NULL, "Invalid arguments",); + CHECK(dst != NULL, "Sanity",); CHECK(size > 0, "Invalid size",); for (i64 i = 0; i < size; ++i) @@ -632,8 +649,8 @@ void mem_set(void *dst, u8 val, i64 size) { } void mem_cpy(void *dst, void *__restrict src, i64 size) { - CHECK(dst != NULL, "Invalid arguments",); - CHECK(src != NULL, "Invalid arguments",); + CHECK(dst != NULL, "Sanity",); + CHECK(src != NULL, "Sanity",); CHECK(size >= 0, "Invalid size",); for (i64 i = 0; i < size; ++i) @@ -641,8 +658,8 @@ void mem_cpy(void *dst, void *__restrict src, i64 size) { } b8 mem_eq(void *a, void *b, i64 size) { - CHECK(a != NULL, "Invalid arguments", 0); - CHECK(b != NULL, "Invalid arguments", 0); + CHECK(a != NULL, "Sanity", 0); + CHECK(b != NULL, "Sanity", 0); CHECK(size > 0, "Invalid size", 0); u8 *x = (u8 *) a; @@ -681,8 +698,8 @@ i64 str_len_or(c8 *s, c8 *s_max, i64 or_val) { } c8 *find_char(c8 *s, c8 *s_end, c8 c) { - CHECK(s != NULL, "Invalid arguments", NULL); - CHECK(s_end != NULL, "Invalid arguments", NULL); + CHECK(s != NULL, "Sanity", NULL); + CHECK(s_end != NULL, "Sanity", NULL); while (s < s_end && *s != c) ++s; @@ -691,10 +708,10 @@ c8 *find_char(c8 *s, c8 *s_end, c8 c) { } c8 *find_str(c8 *s, c8 *s_end, c8 *sub, c8 *sub_end) { - CHECK(s != NULL, "Invalid arguments", NULL); - CHECK(s_end != NULL, "Invalid arguments", NULL); - CHECK(sub != NULL, "Invalid arguments", NULL); - CHECK(sub_end != NULL, "Invalid arguments", NULL); + CHECK(s != NULL, "Sanity", NULL); + CHECK(s_end != NULL, "Sanity", NULL); + CHECK(sub != NULL, "Sanity", NULL); + CHECK(sub_end != NULL, "Sanity", NULL); while (sub_end - sub <= s_end - s && s < s_end) { c8 *q = s; @@ -711,10 +728,10 @@ c8 *find_str(c8 *s, c8 *s_end, c8 *sub, c8 *sub_end) { } c8 *find_str_in_table(c8 *buf, c8 *buf_end, c8 *sub, c8 *sub_end) { - CHECK(buf != NULL, "Invalid arguments", NULL); - CHECK(buf_end != NULL, "Invalid arguments", NULL); - CHECK(sub != NULL, "Invalid arguments", NULL); - CHECK(sub_end != NULL, "Invalid arguments", NULL); + CHECK(buf != NULL, "Sanity", NULL); + CHECK(buf_end != NULL, "Sanity", NULL); + CHECK(sub != NULL, "Sanity", NULL); + CHECK(sub_end != NULL, "Sanity", NULL); while (buf < buf_end) { i64 len = str_len(buf, buf_end); @@ -727,7 +744,7 @@ c8 *find_str_in_table(c8 *buf, c8 *buf_end, c8 *sub, c8 *sub_end) { } u64 u64_from_dec_str(c8 *s, c8 *s_end) { - CHECK(s != NULL && s_end != NULL, "Invalid arguments", 0); + CHECK(s != NULL && s_end != NULL, "Sanity", 0); CHECK(s < s_end, "Buffer overflow", 0); CHECK(*s >= '0' && *s <= '9', "Parsing failed", 0); @@ -738,15 +755,17 @@ u64 u64_from_dec_str(c8 *s, c8 *s_end) { LAX(s == s_end || *s == ' ' || *s == '\0', "Parsing failed"); return x; } + // ================================================================ // // * Chunk table and entity pool // // ================================================================ + Chunk_Handle chunk_add(Pool *pool, i64 size, void *data) { - CHECK(pool != NULL, "Invalid arguments", (Chunk_Handle) {0}); - CHECK(size > 0, "Invalid arguments", (Chunk_Handle) {0}); - CHECK(data != NULL, "Invalid arguments", (Chunk_Handle) {0}); + CHECK(pool != NULL, "Sanity", (Chunk_Handle) {0}); + CHECK(size > 0, "Sanity", (Chunk_Handle) {0}); + CHECK(data != NULL, "Sanity", (Chunk_Handle) {0}); i64 chunk_size = align(size, CHUNK_TABLE_ALIGNMENT); @@ -773,9 +792,9 @@ void chunk_remove(Pool *pool, Chunk_Handle h) { __attribute__ ((warn_unused_result)) #endif Chunk_Handle chunk_resize(Pool *pool, Chunk_Handle h, i64 size) { - CHECK(pool != NULL, "Invalid arguments", (Chunk_Handle) {0}); - CHECK(size > 0, "Invalid arguments", (Chunk_Handle) {0}); - CHECK(h.offset >= 0 && h.size >= 0, "Invalid arguments", (Chunk_Handle) {0}); + CHECK(pool != NULL, "Sanity", (Chunk_Handle) {0}); + CHECK(size > 0, "Sanity", (Chunk_Handle) {0}); + CHECK(h.offset >= 0 && h.size >= 0, "Sanity", (Chunk_Handle) {0}); CHECK(h.offset + h.size <= pool->size, "Invalid handle", (Chunk_Handle) {0}); i64 chunk_size = align(size, CHUNK_TABLE_ALIGNMENT); @@ -813,8 +832,8 @@ Chunk_Handle chunk_resize(Pool *pool, Chunk_Handle h, i64 size) { } u8 *chunk(Pool *pool, Chunk_Handle h) { - CHECK(pool != NULL, "Invalid arguments", NULL); - CHECK(h.offset >= 0 && h.size >= 0, "Invalid arguments", pool->data); + CHECK(pool != NULL, "Sanity", NULL); + CHECK(h.offset >= 0 && h.size >= 0, "Sanity", pool->data); CHECK(h.offset + h.size <= pool->size, "Invalid handle", pool->data); if (h.size == 0) @@ -826,7 +845,7 @@ u8 *chunk(Pool *pool, Chunk_Handle h) { #define CHUNK(pool_, handle_, type_) ((type_ *) chunk((pool_), (handle_))) b8 entity_enabled(Pool *pool, i64 id) { - CHECK(pool != NULL, "Invalid arguments", 0); + CHECK(pool != NULL, "Sanity", 0); CHECK(id != UNDEFINED, "Undefined", 0); CHECK(id > 0 && id < pool->entities.size / (i64) sizeof(Entity), "Invalid id", 0); Entity *entities = CHUNK(pool, pool->entities, Entity); @@ -835,7 +854,7 @@ b8 entity_enabled(Pool *pool, i64 id) { } i64 pool_add(Pool *pool, Entity data) { - CHECK(pool != NULL && pool->data != NULL, "Invalid arguments", UNDEFINED); + CHECK(pool != NULL && pool->data != NULL, "Sanity", UNDEFINED); i64 num_entities = pool->entities.size / sizeof(Entity); if (num_entities == UNDEFINED) @@ -855,7 +874,7 @@ i64 pool_add(Pool *pool, Entity data) { } void pool_remove(Pool *pool, i64 entity, u16 type) { - CHECK(pool != NULL && pool->data != NULL, "Invalid arguments",); + CHECK(pool != NULL && pool->data != NULL, "Sanity",); i64 num_entities = pool->entities.size / sizeof(Entity); Entity *entities = CHUNK(pool, pool->entities, Entity); @@ -868,13 +887,15 @@ void pool_remove(Pool *pool, i64 entity, u16 type) { entities[entity] = (Entity) {0}; } + // ================================================================ // // * Semantic graph // // ================================================================ + Node *node_by_id(Pool *pool, i64 id) { - CHECK(pool != NULL && pool->data != NULL, "Invalid arguments", NULL); + CHECK(pool != NULL && pool->data != NULL, "Sanity", NULL); i64 num_entities = pool->entities.size / sizeof(Entity); Entity *entities = CHUNK(pool, pool->entities, Entity); @@ -889,7 +910,7 @@ Node *node_by_id(Pool *pool, i64 id) { } Proc *proc_by_id(Pool *pool, i64 id) { - CHECK(pool != NULL && pool->data != NULL, "Invalid arguments", NULL); + CHECK(pool != NULL && pool->data != NULL, "Sanity", NULL); i64 num_entities = pool->entities.size / sizeof(Entity); Entity *entities = CHUNK(pool, pool->entities, Entity); @@ -904,7 +925,7 @@ Proc *proc_by_id(Pool *pool, i64 id) { } Unit *unit_by_id(Pool *pool, i64 id) { - CHECK(pool != NULL && pool->data != NULL, "Invalid arguments", NULL); + CHECK(pool != NULL && pool->data != NULL, "Sanity", NULL); i64 num_entities = pool->entities.size / sizeof(Entity); Entity *entities = CHUNK(pool, pool->entities, Entity); @@ -934,42 +955,42 @@ void node_destroy(Pool *pool, i64 node) { i64 node_data_reference(Pool *pool, i64 node) { return node_init(pool, (Node) { - .op = DATA_REFERENCE, + .op = OP_ADDRESS, .ref = node, }); } i64 node_data_array_c8(Pool *pool, i64 size, c8 *data) { return node_init(pool, (Node) { - .op = DATA_I8, + .op = OP_I8, .lit = chunk_add(pool, size, data), }); } i64 node_data_ptr(Pool *pool, u64 address) { return node_init(pool, (Node) { - .op = DATA_PTR, + .op = OP_PTR, .lit = chunk_add(pool, sizeof address, &address), }); } i64 node_data_i32(Pool *pool, i32 value) { return node_init(pool, (Node) { - .op = DATA_I32, + .op = OP_I32, .lit = chunk_add(pool, sizeof value, &value), }); } i64 node_data_i64(Pool *pool, i64 value) { return node_init(pool, (Node) { - .op = DATA_I64, + .op = OP_I64, .lit = chunk_add(pool, sizeof value, &value), }); } i64 node_data_add(Pool *pool, Var x, Var y) { return node_init(pool, (Node) { - .op = DATA_ADD, + .op = OP_ADD, .bin_op = { x, y, @@ -979,7 +1000,7 @@ 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, + .op = OP_SUB, .bin_op = { x, y, @@ -999,7 +1020,7 @@ u16 resolve_calling_convention(Pool *pool, i64 proc) { i64 node_ctrl_call(Pool *pool, i64 target_proc, i64 num_args, Var *args) { return node_init(pool, (Node) { - .op = CTRL_CALL, + .op = OP_CALL, .call = { .convention = resolve_calling_convention(pool, target_proc), .target_proc = target_proc, @@ -1010,7 +1031,7 @@ 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) { return node_init(pool, (Node) { - .op = CTRL_CALL, + .op = OP_CALL, .call = { .convention = CONV_CDECL, .target_proc = UNDEFINED, @@ -1022,7 +1043,7 @@ i64 node_ctrl_call_by_name(Pool *pool, i64 name_size, c8 *name, i64 num_args, Va i64 node_ctrl_ret(Pool *pool, i64 num_values, Var *values) { return node_init(pool, (Node) { - .op = CTRL_RET, + .op = OP_RET, .ret = { .vals = chunk_add(pool, num_values * sizeof *values, values) }, @@ -1075,7 +1096,7 @@ void proc_node_add(Pool *pool, i64 proc, i64 node) { i64 index = num_nodes++; - if (n->op == CTRL_RET) { + if (n->op == OP_RET) { // Only one return node is allowed. CHECK(p->ret_index == UNDEFINED, "Internal",); p->ret_index = index; @@ -1104,7 +1125,7 @@ void proc_node_remove(Pool *pool, i64 proc, i64 node) { CHECK(n->index_in_proc < p->nodes.size / (i64) sizeof(i64), "Buffer overflow",); CHECK(nodes[n->index_in_proc] == node, "Internal",); - if (n->op == CTRL_RET) { + if (n->op == OP_RET) { CHECK(p->ret_index != UNDEFINED, "Internal",); p->ret_index = UNDEFINED; } @@ -1248,6 +1269,7 @@ void unit_set_entry_point(Pool *pool, i64 unit, i64 entry_point_proc) { u->entry_point_index = p->index_in_unit; } + // ================================================================ // // * Serialization @@ -1266,6 +1288,7 @@ void unit_set_entry_point(Pool *pool, i64 unit, i64 entry_point_proc) { // qword = 8 bytes // // ================================================================ + enum { BIT_LE = 0, BIT_BE = 1, @@ -1347,7 +1370,7 @@ u32 host_data_ordering(void) { } u8 read_u8(u32 ordering, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments", 0); + CHECK(v != NULL, "Sanity", 0); CHECK(v < v_end, "Buffer overflow", 0); if ((ordering & BIT_ORDER_MASK) == host_bit_order()) @@ -1365,7 +1388,7 @@ u8 read_u8(u32 ordering, u8 *v, u8 *v_end) { } u16 read_u16(u32 ordering, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments", 0); + CHECK(v != NULL, "Sanity", 0); CHECK(v + 2 <= v_end, "Buffer overflow", 0); u16 x; @@ -1384,7 +1407,7 @@ u16 read_u16(u32 ordering, u8 *v, u8 *v_end) { } u32 read_u32(u32 ordering, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments", 0); + CHECK(v != NULL, "Sanity", 0); CHECK(v + 4 <= v_end, "Buffer overflow", 0); u32 x; @@ -1404,7 +1427,7 @@ u32 read_u32(u32 ordering, u8 *v, u8 *v_end) { } u64 read_u64(u32 ordering, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments", 0); + CHECK(v != NULL, "Sanity", 0); CHECK(v + 8 <= v_end, "Buffer overflow", 0); u64 x; @@ -1425,7 +1448,7 @@ u64 read_u64(u32 ordering, u8 *v, u8 *v_end) { } void write_u8(u8 ordering, u8 x, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments",); + CHECK(v != NULL, "Sanity",); CHECK(v < v_end, "Buffer overflow",); if ((ordering & BIT_ORDER_MASK) == host_bit_order()) @@ -1443,7 +1466,7 @@ void write_u8(u8 ordering, u8 x, u8 *v, u8 *v_end) { } void write_u16(u32 ordering, u16 x, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments",); + CHECK(v != NULL, "Sanity",); CHECK(v + 2 <= v_end, "Buffer overflow",); if ((ordering & BIT_ORDER_MASK) == host_bit_order() && @@ -1459,7 +1482,7 @@ void write_u16(u32 ordering, u16 x, u8 *v, u8 *v_end) { } void write_u32(u32 ordering, u32 x, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments",); + CHECK(v != NULL, "Sanity",); CHECK(v + 4 <= v_end, "Buffer overflow",); if ((ordering & BIT_ORDER_MASK) == host_bit_order() && @@ -1476,7 +1499,7 @@ void write_u32(u32 ordering, u32 x, u8 *v, u8 *v_end) { } void write_u64(u32 ordering, u64 x, u8 *v, u8 *v_end) { - CHECK(v != NULL, "Invalid arguments",); + CHECK(v != NULL, "Sanity",); CHECK(v + 8 <= v_end, "Buffer overflow",); if ((ordering & BIT_ORDER_MASK) == host_bit_order() && @@ -1559,6 +1582,7 @@ void write_f64(u32 ordering, f64 x, void *v, void *v_end) { // Shortcuts #define HO host_data_ordering() + // ================================================================ // // * Code generation and linking @@ -1600,6 +1624,7 @@ void write_f64(u32 ordering, f64 x, void *v, void *v_end) { // TODO Experiment with mapping several p_vaddr into one p_paddr. // // ================================================================ + enum { OS_Unknown = 0, OS_Unix, @@ -1885,14 +1910,29 @@ typedef struct { u32 type; i64 addent; } Elf_Relx_Entry; + // ================================================================ // // Codegen // // ================================================================ + +enum { + EAX = 1, + EBX, + ECX, + EDX, + ESI, + EDI, + + MOV = 1, + ADD, + SUB, +}; + void codegen_add_rel(Pool *pool, Codegen_Context *codegen, Codegen_Rel_Entry rel) { - CHECK(pool != NULL, "Invalid arguments",); - CHECK(codegen != NULL, "Invalid arguments",); + CHECK(pool != NULL, "Sanity",); + CHECK(codegen != NULL, "Sanity",); i64 n = codegen->rels.size / sizeof(Codegen_Rel_Entry); codegen->rels = chunk_resize(pool, codegen->rels, (n + 1) * sizeof(Codegen_Rel_Entry)); @@ -1902,1176 +1942,355 @@ void codegen_add_rel(Pool *pool, Codegen_Context *codegen, Codegen_Rel_Entry rel rels[n] = rel; } -void x86_64_emit_node( +b8 x86_64_emit_i32_mov_reg_val( Pool * pool, Codegen_Context *codegen, - Codegen_Entity *proc, - i64 node, - u32 context + i64 dst, + u32 src ) { - // FIXME Return success status. - // TODO Log generated asm. - - Node *n = node_by_id(pool, node); - CHECK(n != NULL, "No node",); - - codegen->buffer_code = chunk_resize(pool, codegen->buffer_code, codegen->offset_code + 64); + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; u8 *end = begin + codegen->buffer_code.size; - CHECK(begin != NULL, "Internal",); - CHECK(end != NULL, "Internal",); - - i64 num_entities = pool->entities.size / (i64) sizeof(Entity); - - if (codegen->entities.size / (i64) sizeof(Codegen_Entity) != num_entities) - codegen->entities = chunk_resize(pool, codegen->entities, num_entities * sizeof(Codegen_Entity)); - CHECK(num_entities == codegen->entities.size / (i64) sizeof(Codegen_Entity), "Buffer overflow",); - - Codegen_Entity *entities = CHUNK(pool, codegen->entities, Codegen_Entity); - CHECK(entities != NULL, "Internal",); - - switch (n->op) { - case DATA_PTR: - case DATA_I8: - case DATA_I32: - case DATA_I64: - case DATA_REFERENCE: - // Do nothing - break; - - case DATA_ADD: { - // NOTE Assuming static single-assignment form. - - Node *x = node_by_id(pool, n->bin_op[0]); - Node *y = node_by_id(pool, n->bin_op[1]); - - CHECK(x != NULL, "No node",); - CHECK(y != NULL, "No 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: { - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xb8, begin, end); // mov eax - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[0]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xd8, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - // ecx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xc8, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - case 4: - // edx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xd0, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x05, begin, end); // add eax - write_u32(LE, val, begin + 1, end); - - codegen->offset_code += 5; - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[1]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - - write_u8(LE, 0x01, begin, end); // add eax - write_u8(LE, 0xc0, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x01, begin, end); // add eax - write_u8(LE, 0xd8, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - // ecx - - write_u8(LE, 0x01, begin, end); // add eax - write_u8(LE, 0xc8, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - case 4: - // edx - - write_u8(LE, 0x01, begin, end); // add eax - write_u8(LE, 0xd0, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - } break; - - case 2: { - // ebx - - switch (x->op) { - case DATA_I32: { - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xbb, begin, end); // mov ebx - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[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",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x81, begin, end); // add ebx - write_u8 (LE, 0xc3, begin + 1, end); - write_u32(LE, val, begin + 2, end); - - codegen->offset_code += 6; - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[1]].reg; - - switch (src_reg) { - case 1: - // eax - - write_u8(LE, 0x01, begin, end); // add ebx - write_u8(LE, 0xc3, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x01, begin, end); // add ebx - write_u8(LE, 0xdb, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - - write_u8(LE, 0x01, begin, end); // add ebx - write_u8(LE, 0xcb, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x01, begin, end); // add ebx - write_u8(LE, 0xd3, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - } break; - - case 3: { - // ecx - - switch (x->op) { - case DATA_I32: { - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xb9, begin, end); // mov ecx - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[0]].reg; - - switch (src_reg) { - case 1: - // eax - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xc1, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - // ebx - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xd9, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xd1, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x81, begin, end); // add ecx - write_u8 (LE, 0xc1, begin + 1, end); - write_u32(LE, val, begin + 2, end); - - codegen->offset_code += 6; - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[1]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - - write_u8(LE, 0x01, begin, end); // add ecx - write_u8(LE, 0xc1, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - // ebx - - write_u8(LE, 0x01, begin, end); // add ecx - write_u8(LE, 0xd9, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - - write_u8(LE, 0x01, begin, end); // add ecx - write_u8(LE, 0xc9, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x01, begin, end); // add ecx - write_u8(LE, 0xd1, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - } break; - - case 4: { - // edx + switch (dst) { + case EAX: write_u8 (LE, 0xb8, begin, end); break; + case EBX: write_u8 (LE, 0xbb, begin, end); break; + case ECX: write_u8 (LE, 0xb9, begin, end); break; + case EDX: write_u8 (LE, 0xba, begin, end); break; + case ESI: write_u8 (LE, 0xbe, begin, end); break; + case EDI: write_u8 (LE, 0xbf, begin, end); break; + default: FAIL("Not implemented", 0); + } + write_u32(LE, src, begin + 1, end); + codegen->offset_code += 5; + return 1; +} - switch (x->op) { - case DATA_I32: { - u32 val = CHUNK(pool, x->lit, u32)[0]; +b8 x86_64_emit_i32_add_reg_val( + Pool * pool, + Codegen_Context *codegen, + i64 dst, + u32 src +) { + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); - write_u8 (LE, 0xba, begin, end); // mov edx - write_u32(LE, val, begin + 1, end); + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; - begin += 5; - codegen->offset_code += 5; - } break; + if (dst == EAX) { + write_u8 (LE, 0x05, begin, end); + write_u32(LE, src, begin + 1, end); + codegen->offset_code += 5; + return 1; + } - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[0]].reg; + write_u8(LE, 0x81, begin, end); + switch (dst) { + case EBX: write_u8 (LE, 0xc3, begin + 1, end); break; + case ECX: write_u8 (LE, 0xc1, begin + 1, end); break; + case EDX: write_u8 (LE, 0xc2, begin + 1, end); break; + case ESI: write_u8 (LE, 0xc6, begin + 1, end); break; + case EDI: write_u8 (LE, 0xc7, begin + 1, end); break; + default: FAIL("Not implemented", 0); + } + write_u32(LE, src, begin + 2, end); + codegen->offset_code += 6; + return 1; +} - switch (src_reg) { - case 1: - // eax +b8 x86_64_emit_i32_sub_reg_val( + Pool * pool, + Codegen_Context *codegen, + i64 dst, + u32 src +) { + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); - write_u8(LE, 0x89, begin, end); // mov edx - write_u8(LE, 0xc2, begin + 1, end); // eax + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; - begin += 2; - codegen->offset_code += 2; - break; + if (dst == EAX) { + write_u8 (LE, 0x2d, begin, end); + write_u32(LE, src, begin + 1, end); + codegen->offset_code += 5; + return 1; + } - case 2: - // ebx + write_u8(LE, 0x81, begin, end); + switch (dst) { + case EBX: write_u8(LE, 0xeb, begin + 1, end); break; + case ECX: write_u8(LE, 0xe9, begin + 1, end); break; + case EDX: write_u8(LE, 0xea, begin + 1, end); break; + case ESI: write_u8(LE, 0xee, begin + 1, end); break; + case EDI: write_u8(LE, 0xef, begin + 1, end); break; + default: FAIL("Not implemented", 0); + } + write_u32(LE, src, begin + 2, end); + codegen->offset_code += 6; + return 1; +} - write_u8(LE, 0x89, begin, end); // mov edx - write_u8(LE, 0xda, begin + 1, end); // ebx +b8 x86_64_emit_i32_op_reg_args( + Pool * pool, + Codegen_Context *codegen, + i64 dst, + i64 src +) { + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); - begin += 2; - codegen->offset_code += 2; - break; + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; - case 3: - FAIL("Not implemented",); - // ecx + switch (dst) { + case EAX: + switch (src) { + case EAX: write_u8(LE, 0xc0, begin, end); break; + case EBX: write_u8(LE, 0xd8, begin, end); break; + case ECX: write_u8(LE, 0xc8, begin, end); break; + case EDX: write_u8(LE, 0xd0, begin, end); break; + case ESI: write_u8(LE, 0xf0, begin, end); break; + case EDI: write_u8(LE, 0xf8, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - write_u8(LE, 0x89, begin, end); // mov edx - write_u8(LE, 0xca, begin + 1, end); // ecx + case EBX: + switch (src) { + case EAX: write_u8(LE, 0xc3, begin, end); break; + case EBX: write_u8(LE, 0xd3, begin, end); break; + case ECX: write_u8(LE, 0xcb, begin, end); break; + case EDX: write_u8(LE, 0xd3, begin, end); break; + case ESI: write_u8(LE, 0xf3, begin, end); break; + case EDI: write_u8(LE, 0xfb, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - begin += 2; - codegen->offset_code += 2; - break; + case ECX: + switch (src) { + case EAX: write_u8(LE, 0xc1, begin, end); break; + case EBX: write_u8(LE, 0xd9, begin, end); break; + case ECX: write_u8(LE, 0xc9, begin, end); break; + case EDX: write_u8(LE, 0xd1, begin, end); break; + case ESI: write_u8(LE, 0xf1, begin, end); break; + case EDI: write_u8(LE, 0xf9, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - case 4: - FAIL("Not implemented",); - // edx - break; + case EDX: + switch (src) { + case EAX: write_u8(LE, 0xc2, begin, end); break; + case EBX: write_u8(LE, 0xda, begin, end); break; + case ECX: write_u8(LE, 0xca, begin, end); break; + case EDX: write_u8(LE, 0xd2, begin, end); break; + case ESI: write_u8(LE, 0xf2, begin, end); break; + case EDI: write_u8(LE, 0xfa, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - default: - FAIL("Not implemented",); - } + case ESI: + switch (src) { + case EAX: write_u8(LE, 0xc6, begin, end); break; + case EBX: write_u8(LE, 0xde, begin, end); break; + case ECX: write_u8(LE, 0xce, begin, end); break; + case EDX: write_u8(LE, 0xd6, begin, end); break; + case ESI: write_u8(LE, 0xf6, begin, end); break; + case EDI: write_u8(LE, 0xfe, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; + case EDI: + switch (src) { + case EAX: write_u8(LE, 0xc7, begin, end); break; + case EBX: write_u8(LE, 0xdf, begin, end); break; + case ECX: write_u8(LE, 0xcf, begin, end); break; + case EDX: write_u8(LE, 0xd7, begin, end); break; + case ESI: write_u8(LE, 0xf7, begin, end); break; + case EDI: write_u8(LE, 0xff, begin, end); break; + default: FAIL("Not implemented", 0); + } + break; - default: - FAIL("Not implemented",); - } + default: FAIL("Not implemented", 0); + } + ++codegen->offset_code; + return 1; +} - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; +b8 x86_64_emit_i32_op_reg_val( + Pool * pool, + Codegen_Context *codegen, + i64 op, + i64 dst, + u32 src +) { + switch (op) { + case MOV: LOG(VERBOSE, "+ mov [%lld], %u", dst, src); return x86_64_emit_i32_mov_reg_val(pool, codegen, dst, src); + case ADD: LOG(VERBOSE, "+ add [%lld], %u", dst, src); return x86_64_emit_i32_add_reg_val(pool, codegen, dst, src); + case SUB: LOG(VERBOSE, "+ sub [%lld], %u", dst, src); return x86_64_emit_i32_sub_reg_val(pool, codegen, dst, src); + default:; + } - write_u8 (LE, 0x81, begin, end); // add edx - write_u8 (LE, 0xc2, begin + 1, end); - write_u32(LE, val, begin + 2, end); + FAIL("Sanity", 0); +} - codegen->offset_code += 6; - } break; +b8 x86_64_emit_i32_op_reg_reg( + Pool * pool, + Codegen_Context *codegen, + i64 op, + i64 dst, + i64 src +) { + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[1]].reg; + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax + if (dst == src) + return 1; - write_u8(LE, 0x01, begin, end); // add edx - write_u8(LE, 0xc2, begin + 1, end); // eax + switch (op) { + case MOV: LOG(VERBOSE, "+ mov [%lld], [%lld]", dst, src); write_u8(LE, 0x89, begin, end); break; + case ADD: LOG(VERBOSE, "+ add [%lld], [%lld]", dst, src); write_u8(LE, 0x01, begin, end); break; + case SUB: LOG(VERBOSE, "+ sub [%lld], [%lld]", dst, src); write_u8(LE, 0x29, begin, end); break; + default: FAIL("Not implemented", 0); + } + ++codegen->offset_code; - begin += 2; - codegen->offset_code += 2; - break; + return x86_64_emit_i32_op_reg_args(pool, codegen, dst, src); +} - case 2: - // ebx +b8 x86_64_emit_node( + Pool * pool, + Codegen_Context *codegen, + Codegen_Entity *proc, + i64 node, + u32 context +) { + Node *n = node_by_id(pool, node); + CHECK(n != NULL, "No node", 0); - write_u8(LE, 0x01, begin, end); // add edx - write_u8(LE, 0xda, begin + 1, end); // ebx + codegen->buffer_code = chunk_resize(pool, codegen->buffer_code, codegen->offset_code + 256); + CHECK(codegen->buffer_code.size == codegen->offset_code + 256, "Buffer overflow", 0); - begin += 2; - codegen->offset_code += 2; - break; + i64 num_entities = pool->entities.size / (i64) sizeof(Entity); - case 3: - // ecx + if (codegen->entities.size / (i64) sizeof(Codegen_Entity) != num_entities) + codegen->entities = chunk_resize(pool, codegen->entities, num_entities * sizeof(Codegen_Entity)); + CHECK(num_entities == codegen->entities.size / (i64) sizeof(Codegen_Entity), "Buffer overflow", 0); - write_u8(LE, 0x01, begin, end); // add edx - write_u8(LE, 0xca, begin + 1, end); // ecx + Codegen_Entity *entities = CHUNK(pool, codegen->entities, Codegen_Entity); + CHECK(entities != NULL, "Internal", 0); - begin += 2; - codegen->offset_code += 2; - break; + switch (n->op) { + case OP_PTR: + case OP_I8: + case OP_I32: + case OP_I64: + case OP_ADDRESS: + // Do nothing + break; - case 4: - FAIL("Not implemented",); - // edx + case OP_ADD: + case OP_SUB: { + // NOTE Assuming static single-assignment form. - write_u8(LE, 0x01, begin, end); // add edx - write_u8(LE, 0xd2, begin + 1, end); // edx + Node * x_n = node_by_id(pool, n->bin_op[0]); + Node * y_n = node_by_id(pool, n->bin_op[1]); + Codegen_Entity *x = entities + n->bin_op[0]; + Codegen_Entity *y = entities + n->bin_op[1]; + Codegen_Entity *dst = entities + node; - begin += 2; - codegen->offset_code += 2; - break; + CHECK(x_n != NULL, "Sanity", 0); + CHECK(y_n != NULL, "Sanity", 0); + CHECK(x != NULL, "Sanity", 0); + CHECK(y != NULL, "Sanity", 0); - default: - FAIL("Not implemented",); - } + dst->reg = 1; + while (dst->reg <= 6 && ((1 << (dst->reg - 1)) & proc->occupied_reg) != 0) + ++dst->reg; - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; + i64 op = n->op == OP_ADD ? ADD : SUB; - default: - FAIL("Not implemented",); - } + switch (x_n->op) { + case OP_I32: { + u32 val = CHUNK(pool, x_n->lit, u32)[0]; + if (!x86_64_emit_i32_op_reg_val(pool, codegen, MOV, dst->reg, val)) + return 0; } break; - case 5: { - // esi - - switch (x->op) { - case DATA_I32: { - FAIL("Not implemented",); - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[0]].reg; - - switch (src_reg) { - case 1: - // eax - - write_u8(LE, 0x89, begin, end); // mov esi - write_u8(LE, 0xc6, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x89, begin, end); // mov esi - write_u8(LE, 0xde, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - - write_u8(LE, 0x89, begin, end); // mov esi - write_u8(LE, 0xce, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x89, begin, end); // mov esi - write_u8(LE, 0xd6, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - FAIL("Not implemented",); - } break; - - case DATA_ADD: { - i64 src_reg = entities[n->bin_op[1]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - - write_u8(LE, 0x01, begin, end); // add esi - write_u8(LE, 0xc6, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - // ebx - - write_u8(LE, 0x01, begin, end); // add esi - write_u8(LE, 0xde, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - - write_u8(LE, 0x01, begin, end); // add esi - write_u8(LE, 0xce, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x01, begin, end); // add esi - write_u8(LE, 0xd6, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - } break; + case OP_ADD: + case OP_SUB: + if (!x86_64_emit_i32_op_reg_reg(pool, codegen, MOV, dst->reg, x->reg)) + return 0; + proc->occupied_reg &= ~(1 << (x->reg - 1)); + x->reg = 0; + break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } - entities[node].reg = dst_reg; - proc->occupied_reg |= 1 << (dst_reg - 1); - } break; - - case DATA_SUB: { - // NOTE Assuming static single-assignment form. - - Node *x = node_by_id(pool, n->bin_op[0]); - Node *y = node_by_id(pool, n->bin_op[1]); - - CHECK(x != NULL, "No node",); - CHECK(y != NULL, "No 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: { - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xb8, begin, end); // mov eax - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[0]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xd8, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - // ecx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xc8, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x89, begin, end); // mov eax - write_u8(LE, 0xd0, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x2d, begin, end); // sub eax - write_u32(LE, val, begin + 1, end); - - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - FAIL("Not implemented",); - } break; - - default: - FAIL("Not implemented",); - } + switch (y_n->op) { + case OP_I32: { + u32 val = CHUNK(pool, y_n->lit, u32)[0]; + if (!x86_64_emit_i32_op_reg_val(pool, codegen, op, dst->reg, val)) + return 0; } break; - case 2: { - // ebx - - switch (x->op) { - case DATA_I32: { - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xbb, begin, end); // mov ebx - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[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: - FAIL("Not implemented",); - // 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: - FAIL("Not implemented",); - // 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",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x81, begin, end); // sub ebx - write_u8 (LE, 0xeb, begin + 1, end); - write_u32(LE, val, 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: { - // ecx - - switch (x->op) { - case DATA_I32: { - FAIL("Not implemented",); - - u32 val = CHUNK(pool, x->lit, u32)[0]; - - write_u8 (LE, 0xb9, begin, end); // mov ecx - write_u32(LE, val, begin + 1, end); - - begin += 5; - codegen->offset_code += 5; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[0]].reg; - - switch (src_reg) { - case 1: - // eax - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xc1, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - FAIL("Not implemented",); - // ebx - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xd9, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xd1, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - case 5: - FAIL("Not implemented",); - // esi - - write_u8(LE, 0x89, begin, end); // mov ecx - write_u8(LE, 0xf1, begin + 1, end); // esi - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[0]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - - switch (y->op) { - case DATA_I32: { - FAIL("Not implemented",); - - u32 val = CHUNK(pool, y->lit, u32)[0]; - - write_u8 (LE, 0x81, begin, end); // sub ecx - write_u8 (LE, 0xe9, begin + 1, end); - write_u32(LE, val, begin + 2, end); - - codegen->offset_code += 6; - } break; - - case DATA_ADD: - case DATA_SUB: { - i64 src_reg = entities[n->bin_op[1]].reg; - - switch (src_reg) { - case 1: - FAIL("Not implemented",); - // eax - - write_u8(LE, 0x29, begin, end); // sub ecx - write_u8(LE, 0xc1, begin + 1, end); // eax - - begin += 2; - codegen->offset_code += 2; - break; - - case 2: - // ebx - - write_u8(LE, 0x29, begin, end); // sub ecx - write_u8(LE, 0xd9, begin + 1, end); // ebx - - begin += 2; - codegen->offset_code += 2; - break; - - case 3: - FAIL("Not implemented",); - // ecx - - write_u8(LE, 0x29, begin, end); // sub ecx - write_u8(LE, 0xc9, begin + 1, end); // ecx - - begin += 2; - codegen->offset_code += 2; - break; - - - case 4: - FAIL("Not implemented",); - // edx - - write_u8(LE, 0x29, begin, end); // sub ecx - write_u8(LE, 0xd1, begin + 1, end); // edx - - begin += 2; - codegen->offset_code += 2; - break; - - case 5: - FAIL("Not implemented",); - // esi - - write_u8(LE, 0x29, begin, end); // sub ecx - write_u8(LE, 0xf1, begin + 1, end); // esi - - begin += 2; - codegen->offset_code += 2; - break; - - default: - FAIL("Not implemented",); - } - - entities[n->bin_op[1]].reg = 0; - proc->occupied_reg &= ~(1 << (src_reg - 1)); - } break; - - default: - FAIL("Not implemented",); - } - } break; - - case 4: { - FAIL("Not implemented",); - // edx - } break; - - case 5: { - FAIL("Not implemented",); - // esi - } break; + case OP_ADD: + case OP_SUB: + if (!x86_64_emit_i32_op_reg_reg(pool, codegen, op, dst->reg, y->reg)) + return 0; + proc->occupied_reg &= ~(1 << (y->reg - 1)); + y->reg = 0; + break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } - entities[node].reg = dst_reg; - proc->occupied_reg |= 1 << (dst_reg - 1); + 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",); - CHECK(n->call.target_name.size > 0, "No proc name",); + case OP_CALL: { + CHECK(n->call.convention == CONV_CDECL, "Not implemented", 0); + CHECK(n->call.target_proc == UNDEFINED, "Not implemented", 0); + CHECK(n->call.target_name.size > 0, "No proc name", 0); + + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; i64 num_args = n->call.args.size / sizeof(i64); i64 *args = CHUNK(pool, n->call.args, i64); - CHECK(args != NULL, "Internal",); + CHECK(args != NULL, "Internal", 0); switch (num_args) { case 1: { Node *arg = node_by_id(pool, args[0]); - CHECK(arg != NULL, "No node",); + CHECK(arg != NULL, "No node", 0); - if (arg->op == DATA_REFERENCE) { + if (arg->op == OP_ADDRESS) { // Write data // Node *data = node_by_id(pool, arg->ref); - CHECK(data->op == DATA_I8, "Not implemented",); + CHECK(data->op == OP_I8, "Not implemented", 0); i64 arg_offset = codegen->offset_ro_data; codegen->buffer_ro_data = chunk_resize(pool, codegen->buffer_ro_data, arg_offset + data->lit.size); u8 *buf = CHUNK(pool, codegen->buffer_ro_data, u8); - CHECK(buf != NULL, "Internal",); - CHECK(arg_offset + data->lit.size <= codegen->buffer_ro_data.size, "Buffer overflow",); + CHECK(buf != NULL, "Internal", 0); + CHECK(arg_offset + data->lit.size <= codegen->buffer_ro_data.size, "Buffer overflow", 0); mem_cpy(buf + arg_offset, CHUNK(pool, data->lit, u8), data->lit.size); @@ -3082,7 +2301,7 @@ void x86_64_emit_node( write_u8(LE, 0xbf, begin + 1, end); // rdi codegen_add_rel(pool, codegen, (Codegen_Rel_Entry) { - .type = REL_ADD_RO_DATA_ADDRESS, + .type = REL_ADD_RO_OP_ADDRESS, .offset = codegen->offset_code + 2, .size = 8, .value = arg_offset, @@ -3104,8 +2323,8 @@ void x86_64_emit_node( codegen->offset_code += 22; codegen->offset_ro_data += data->lit.size; - } else if (arg->op == DATA_I32) { - CHECK(arg->lit.size == 4, "Not implemented",); + } else if (arg->op == OP_I32) { + CHECK(arg->lit.size == 4, "Not implemented", 0); i32 val = CHUNK(pool, arg->lit, i32)[0]; @@ -3127,7 +2346,7 @@ void x86_64_emit_node( codegen->offset_code += 13; } else { - FAIL("Not implemented",); + FAIL("Not implemented", 0); } } break; @@ -3136,17 +2355,17 @@ void x86_64_emit_node( Node *arg_1 = node_by_id(pool, args[1]); Node *arg_2 = node_by_id(pool, args[2]); - CHECK(arg_0->op == DATA_PTR, "Not implemented",); - CHECK(arg_1->op == DATA_PTR, "Not implemented",); - CHECK(arg_2->op == DATA_PTR, "Not implemented",); + CHECK(arg_0->op == OP_PTR, "Not implemented", 0); + CHECK(arg_1->op == OP_PTR, "Not implemented", 0); + CHECK(arg_2->op == OP_PTR, "Not implemented", 0); u64 val_0 = CHUNK(pool, arg_0->lit, u64)[0]; u64 val_1 = CHUNK(pool, arg_1->lit, u64)[0]; u64 val_2 = CHUNK(pool, arg_2->lit, u64)[0]; - CHECK(val_0 == 0, "Not implemented",); - CHECK(val_1 == 0, "Not implemented",); - CHECK(val_2 == 0, "Not implemented",); + CHECK(val_0 == 0, "Not implemented", 0); + CHECK(val_1 == 0, "Not implemented", 0); + CHECK(val_2 == 0, "Not implemented", 0); write_u8(LE, 0x31, begin, end); // xor edx write_u8(LE, 0xd2, begin + 1, end); // edx @@ -3180,29 +2399,29 @@ void x86_64_emit_node( Node *arg_5 = node_by_id(pool, args[5]); Node *arg_6 = node_by_id(pool, args[6]); - CHECK(arg_0->op == DATA_REFERENCE, "Not implemented",); - CHECK(arg_1->op == DATA_I32, "Not implemented",); - CHECK(arg_2->op == DATA_REFERENCE, "Not implemented",); - CHECK(arg_3->op == DATA_PTR, "Not implemented",); - CHECK(arg_4->op == DATA_PTR, "Not implemented",); - CHECK(arg_5->op == DATA_PTR, "Not implemented",); - CHECK(arg_6->op == DATA_PTR, "Not implemented",); + CHECK(arg_0->op == OP_ADDRESS, "Not implemented", 0); + CHECK(arg_1->op == OP_I32, "Not implemented", 0); + CHECK(arg_2->op == OP_ADDRESS, "Not implemented", 0); + CHECK(arg_3->op == OP_PTR, "Not implemented", 0); + CHECK(arg_4->op == OP_PTR, "Not implemented", 0); + CHECK(arg_5->op == OP_PTR, "Not implemented", 0); + CHECK(arg_6->op == OP_PTR, "Not implemented", 0); Proc *dat_0 = proc_by_id(pool, arg_0->ref); - CHECK(dat_0 != NULL, "No proc",); + CHECK(dat_0 != NULL, "No proc", 0); // Write data // Node *dat_2 = node_by_id(pool, arg_2->ref); - CHECK(dat_2 != NULL, "No node",); - CHECK(dat_2->op == DATA_PTR, "Not implemented",); + CHECK(dat_2 != NULL, "No node", 0); + CHECK(dat_2->op == OP_PTR, "Not implemented", 0); i64 arg_2_offset = codegen->offset_ro_data; codegen->buffer_ro_data = chunk_resize(pool, codegen->buffer_ro_data, arg_2_offset + dat_2->lit.size); u8 *buf = CHUNK(pool, codegen->buffer_ro_data, u8); - CHECK(buf != NULL, "Internal",); - CHECK(arg_2_offset + dat_2->lit.size <= codegen->buffer_ro_data.size, "Buffer overflow",); + CHECK(buf != NULL, "Internal", 0); + CHECK(arg_2_offset + dat_2->lit.size <= codegen->buffer_ro_data.size, "Buffer overflow", 0); mem_cpy(buf + arg_2_offset, CHUNK(pool, dat_2->lit, u8), dat_2->lit.size); @@ -3227,7 +2446,7 @@ void x86_64_emit_node( write_u8 (LE, 0xba, begin + 16, end); // rdx codegen_add_rel(pool, codegen, (Codegen_Rel_Entry) { - .type = REL_ADD_RO_DATA_ADDRESS, + .type = REL_ADD_RO_OP_ADDRESS, .offset = codegen->offset_code + 17, .size = 8, .value = arg_2_offset, @@ -3284,14 +2503,17 @@ void x86_64_emit_node( } break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } } break; - case CTRL_RET: { + case OP_RET: { + u8 *begin = CHUNK(pool, codegen->buffer_code, u8) + codegen->offset_code; + u8 *end = begin + codegen->buffer_code.size; + i64 num_vals = n->ret.vals.size / sizeof(i64); i64 *vals = CHUNK(pool, n->ret.vals, i64); - CHECK(vals != NULL, "Internal",); + CHECK(vals != NULL, "Internal", 0); if ((context & EMIT_ENTRY_PROC) != 0) { if (num_vals == 0) { @@ -3310,11 +2532,11 @@ void x86_64_emit_node( LOG(WARNING, "Some return values are ignored for node %lld", node); Node *val = node_by_id(pool, vals[0]); - CHECK(val != NULL, "No node",); + CHECK(val != NULL, "No node", 0); switch (val->op) { - case DATA_I64: { - CHECK(val->lit.size == 8, "Not implemented",); + case OP_I64: { + CHECK(val->lit.size == 8, "Not implemented", 0); u32 a = CHUNK(pool, val->lit, u32)[0]; @@ -3330,16 +2552,12 @@ void x86_64_emit_node( codegen->offset_code += 12; } break; - case DATA_ADD: - case DATA_SUB: { + case OP_ADD: + case OP_SUB: { switch (entities[vals[0]].reg) { - case 1: - // eax - break; - - case 2: - // ebx + case EAX: break; + case EBX: write_u8 (LE, 0x89, begin, end); // mov eax write_u8 (LE, 0xd8, begin + 1, end); // ebx @@ -3347,9 +2565,7 @@ void x86_64_emit_node( codegen->offset_code += 2; break; - case 3: - // ecx - + case ECX: write_u8 (LE, 0x89, begin, end); // mov eax write_u8 (LE, 0xc8, begin + 1, end); // ecx @@ -3357,9 +2573,7 @@ void x86_64_emit_node( codegen->offset_code += 2; break; - case 4: - // edx - + case EDX: write_u8 (LE, 0x89, begin, end); // mov eax write_u8 (LE, 0xd0, begin + 1, end); // edx @@ -3368,11 +2582,11 @@ void x86_64_emit_node( break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } write_u8 (LE, 0x89, begin, end); // mov edi - write_u32(LE, 0xc7, begin + 1, end); // eax + write_u8 (LE, 0xc7, begin + 1, end); // eax write_u8 (LE, 0xb8, begin + 2, end); // mov eax write_u32(LE, 60, begin + 3, end); // 60 @@ -3384,17 +2598,17 @@ void x86_64_emit_node( } break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } } } else { - CHECK(num_vals == 1, "Not implemented",); + CHECK(num_vals == 1, "Not implemented", 0); Node *val = node_by_id(pool, vals[0]); switch (val->op) { - case DATA_I32: { - CHECK(val->lit.size == 4, "Not implemented",); + case OP_I32: { + CHECK(val->lit.size == 4, "Not implemented", 0); u32 a = CHUNK(pool, val->lit, u32)[0]; @@ -3405,8 +2619,9 @@ void x86_64_emit_node( codegen->offset_code += 6; } break; - case DATA_ADD: { - CHECK(entities[vals[0]].reg == 1, "Not implemented",); + case OP_ADD: + case OP_SUB: { + CHECK(entities[vals[0]].reg == EAX, "Not implemented", 0); write_u8(LE, 0xc3, begin, end); // ret @@ -3414,65 +2629,70 @@ void x86_64_emit_node( } break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } } } break; default: - FAIL("Unknown operation",); + FAIL("Unknown operation", 0); } + return 1; + #undef CHECK_NODE_ } -void emit_proc( +b8 emit_proc( Pool * pool, Codegen_Context *codegen, i64 proc, u16 arch, u32 context ) { - CHECK(arch == ARCH_X86_64, "Target not supported",); + CHECK(arch == ARCH_X86_64, "Target not supported", 0); Proc *p = proc_by_id(pool, proc); - CHECK(p != NULL, "No proc",); + CHECK(p != NULL, "No proc", 0); i64 num_entities = pool->entities.size / (i64) sizeof(Entity); if (codegen->entities.size / (i64) sizeof(Codegen_Entity) < num_entities) codegen->entities = chunk_resize(pool, codegen->entities, num_entities * sizeof(Codegen_Entity)); - CHECK(codegen->entities.size / (i64) sizeof(Codegen_Entity) >= num_entities, "Buffer overflow",); + CHECK(codegen->entities.size / (i64) sizeof(Codegen_Entity) >= num_entities, "Buffer overflow", 0); Codegen_Entity *entities = CHUNK(pool, codegen->entities, Codegen_Entity); - CHECK(entities != NULL, "Internal",); - CHECK(proc < codegen->entities.size / (i64) sizeof(Codegen_Entity), "Buffer overflow",); - CHECK(entities[proc].emit_done == 0, "Emit already done",); + CHECK(entities != NULL, "Internal", 0); + CHECK(proc < codegen->entities.size / (i64) sizeof(Codegen_Entity), "Buffer overflow", 0); + CHECK(entities[proc].emit_done == 0, "Emit already done", 0); entities[proc].offset = codegen->offset_code; // TODO Sort nodes in the sequential execution order. - // - // NOTE - // Now we assume that nodes are already sorted. + // NOTE Now we assume that nodes are already sorted. i64 num_nodes = p->nodes.size / sizeof(i64); i64 *nodes = CHUNK(pool, p->nodes, i64); - CHECK(nodes != NULL, "Internal",); + CHECK(nodes != NULL, "Internal", 0); for (i64 i = 1; i < num_nodes; ++i) if (entity_enabled(pool, nodes[i])) - x86_64_emit_node(pool, codegen, entities + proc, nodes[i], context); + if (!x86_64_emit_node(pool, codegen, entities + proc, nodes[i], context)) + return 0; entities[proc].emit_done = 1; + return 1; } -void emit_unit(Pool *pool, Codegen_Context *codegen, i64 unit, u16 arch) { +b8 emit_unit(Pool *pool, Codegen_Context *codegen, i64 unit, u16 arch) { + CHECK(pool != NULL, "Sanity", 0); + CHECK(codegen != NULL, "Sanity", 0); + Unit *u = unit_by_id(pool, unit); - CHECK(u != NULL, "No unit",); + CHECK(u != NULL, "No unit", 0); i64 num_procs = u->procs.size / sizeof(i64); i64 *procs = CHUNK(pool, u->procs, i64); - CHECK(procs != NULL, "Internal",); + CHECK(procs != NULL, "Internal", 0); for (i64 i = 1; i < num_procs; ++i) { if (!entity_enabled(pool, procs[i])) @@ -3481,23 +2701,28 @@ void emit_unit(Pool *pool, Codegen_Context *codegen, i64 unit, u16 arch) { u32 context = 0; if (i == u->entry_point_index) { - CHECK(!codegen->has_entry, "Multiple entry points",); + CHECK(!codegen->has_entry, "Multiple entry points", 0); codegen->entry_point = codegen->offset_code; codegen->has_entry = 1; context |= EMIT_ENTRY_PROC; } - emit_proc(pool, codegen, procs[i], arch, context); + if (!emit_proc(pool, codegen, procs[i], arch, context)) + return 0; } + + return 1; } + // ================================================================ // // Linking // // ================================================================ + void link_add_symbol(Pool *pool, Linker_Context *linker, Link_Sym_Entry sym) { - CHECK(pool != NULL, "Invalid arguments",); - CHECK(linker != NULL, "Invalid arguments",); + CHECK(pool != NULL, "Sanity",); + CHECK(linker != NULL, "Sanity",); i64 n = linker->symbols.size / sizeof(Link_Sym_Entry); linker->symbols = chunk_resize(pool, linker->symbols, (n + 1) * sizeof(Link_Sym_Entry)); @@ -3513,9 +2738,9 @@ i64 ar_find_symbol_offset_by_name( c8 *name, c8 *name_end ) { - CHECK(ar_symbol_table != NULL, "Invalid arguments", -1); - CHECK(name != NULL, "Invalid arguments", -1); - CHECK(name_end > name, "Invalid arguments", -1); + CHECK(ar_symbol_table != NULL, "Sanity", -1); + CHECK(name != NULL, "Sanity", -1); + CHECK(name_end > name, "Sanity", -1); i64 num = (i64) read_u32((LE & ~BYTE_ORDER_MASK) | BYTE_BE, ar_symbol_table, ar_end); i64 len = name_end - name; @@ -3626,7 +2851,7 @@ i64 elf_find_section_index_by_name( c8 * name, i64 name_size ) { - CHECK(name != NULL, "Invalid arguments", 0); + CHECK(name != NULL, "Sanity", 0); if (name_size == 0) return 0; @@ -3882,7 +3107,8 @@ i64 unit_write_in_memory( ) { CHECK(format == FORMAT_ELF && arch == ARCH_X86_64, "Target not supported", 0); - emit_unit(pool, codegen, unit, arch); + if (!emit_unit(pool, codegen, unit, arch)) + return 0; u16 num_program_headers = 10; i64 program_offset = align(ELF_HEADER_SIZE + ELF_PROGRAM_HEADER_SIZE * num_program_headers, X86_64_PAGE_SIZE); @@ -4693,7 +3919,7 @@ i64 unit_write_in_memory( write_i64(LE, value, begin, end); } break; - case REL_ADD_RO_DATA_ADDRESS: { + case REL_ADD_RO_OP_ADDRESS: { CHECK(rel.size == 8, "Not implemented", 0); i64 value = rel.value + ro_data_address; write_i64(LE, value, begin, end); @@ -5016,18 +4242,17 @@ i64 unit_write_in_memory( return output_size; } -void unit_write( +b8 unit_write_with_context( Pool * pool, + Codegen_Context *codegen, + Linker_Context * linker, i64 unit, u16 format, u16 arch, i64 io_out, void * io_user_data ) { - Codegen_Context codegen = {0}; - Linker_Context linker = {0}; - - CHECK(unit != UNDEFINED, "Invalid unit",); + CHECK(unit != UNDEFINED, "Invalid unit", 0); // ============================================================== // @@ -5039,15 +4264,15 @@ void unit_write( i64 num_links = u->links.size / sizeof(i64); i64 *links = CHUNK(pool, u->links, i64); - CHECK(links != NULL, "Internal",); + CHECK(links != NULL, "Internal", 0); for (i64 link_index = 1; link_index < num_links; ++link_index) { i64 id = links[link_index]; if (id == UNDEFINED) continue; Unit *l = unit_by_id(pool, id); - CHECK(entity_enabled(pool, id), "Internal",); - CHECK(l->name.size > 0, "No link name",); + CHECK(entity_enabled(pool, id), "Internal", 0); + CHECK(l->name.size > 0, "No link name", 0); switch (l->type) { case UNIT_LIBRARY_OBJECT: { @@ -5056,23 +4281,23 @@ void unit_write( i64 in_size = io_tell(f, io_user_data); - linker.dependencies_buffer = chunk_resize(pool, linker.dependencies_buffer, obj_files_size + in_size); - u8 *dependencies_buffer = CHUNK(pool, linker.dependencies_buffer, u8); - CHECK(dependencies_buffer != NULL, "Internal",); + linker->dependencies_buffer = chunk_resize(pool, linker->dependencies_buffer, obj_files_size + in_size); + u8 *dependencies_buffer = CHUNK(pool, linker->dependencies_buffer, u8); + CHECK(dependencies_buffer != NULL, "Internal", 0); io_seek(f, 0, IO_SEEK_BEGIN, io_user_data); i64 n = io_read(f, in_size, dependencies_buffer + obj_files_size, io_user_data); - CHECK(n == in_size, "Read failed",); + CHECK(n == in_size, "Read failed", 0); io_close(f, io_user_data); - linker.obj_file_offsets = chunk_resize(pool, linker.obj_file_offsets, (linker.num_obj_files + 2) * sizeof(i64)); - i64 *obj_file_offsets = CHUNK(pool, linker.obj_file_offsets, i64); - CHECK(obj_file_offsets != NULL, "Internal",); + linker->obj_file_offsets = chunk_resize(pool, linker->obj_file_offsets, (linker->num_obj_files + 2) * sizeof(i64)); + i64 *obj_file_offsets = CHUNK(pool, linker->obj_file_offsets, i64); + CHECK(obj_file_offsets != NULL, "Internal", 0); - obj_file_offsets[linker.num_obj_files] = obj_files_size; + obj_file_offsets[linker->num_obj_files] = obj_files_size; obj_files_size += align(in_size, X86_64_ALIGNMENT); - obj_file_offsets[++linker.num_obj_files] = obj_files_size; + obj_file_offsets[++linker->num_obj_files] = obj_files_size; } break; case UNIT_LIBRARY_STATIC: { @@ -5081,13 +4306,13 @@ void unit_write( i64 in_size = io_tell(f, io_user_data); - linker.obj_file_buffer = chunk_resize(pool, linker.obj_file_buffer, in_size); - u8 *obj_file_buffer = CHUNK(pool, linker.obj_file_buffer, u8); - CHECK(obj_file_buffer != NULL, "Internal",); + linker->obj_file_buffer = chunk_resize(pool, linker->obj_file_buffer, in_size); + u8 *obj_file_buffer = CHUNK(pool, linker->obj_file_buffer, u8); + CHECK(obj_file_buffer != NULL, "Internal", 0); io_seek(f, 0, IO_SEEK_BEGIN, io_user_data); i64 n = io_read(f, in_size, obj_file_buffer, io_user_data); - CHECK(n == in_size, "Read failed",); + CHECK(n == in_size, "Read failed", 0); io_close(f, io_user_data); @@ -5098,7 +4323,7 @@ void unit_write( u8 *ar_begin = obj_file_buffer; u8 *ar_end = obj_file_buffer + in_size; - CHECK(mem_eq(ar_begin, AR_MAGIC, 8), "Invalid AR file",); + CHECK(mem_eq(ar_begin, AR_MAGIC, 8), "Invalid AR file", 0); u8 *f_begin = ar_begin + 8; @@ -5112,8 +4337,8 @@ void unit_write( size = align(size, 2); - CHECK(mem_eq(f_end, "\x60\x0a", 2), "Invalid AR file",); - CHECK(f_begin + size <= ar_end, "Buffer overflow",); + CHECK(mem_eq(f_end, "\x60\x0a", 2), "Invalid AR file", 0); + CHECK(f_begin + size <= ar_end, "Buffer overflow", 0); if (!mem_eq(f_id, AR_SYMBOL_TABLE, sizeof AR_SYMBOL_TABLE - 1) && !mem_eq(f_id, AR_STRING_TABLE, sizeof AR_STRING_TABLE - 1)) { @@ -5121,17 +4346,17 @@ void unit_write( i64 delta_size = align(size, X86_64_ALIGNMENT); - u8 *dependencies_buffer = CHUNK(pool, linker.dependencies_buffer, u8); - CHECK(dependencies_buffer != NULL, "Internal",); + u8 *dependencies_buffer = CHUNK(pool, linker->dependencies_buffer, u8); + CHECK(dependencies_buffer != NULL, "Internal", 0); mem_cpy(dependencies_buffer + obj_files_size, f_data, size); - i64 *obj_file_offsets = CHUNK(pool, linker.obj_file_offsets, i64); - CHECK(obj_file_offsets != NULL, "Internal",); + i64 *obj_file_offsets = CHUNK(pool, linker->obj_file_offsets, i64); + CHECK(obj_file_offsets != NULL, "Internal", 0); - obj_file_offsets[linker.num_obj_files] = obj_files_size; + obj_file_offsets[linker->num_obj_files] = obj_files_size; obj_files_size += delta_size; - obj_file_offsets[++linker.num_obj_files] = obj_files_size; + obj_file_offsets[++linker->num_obj_files] = obj_files_size; } f_begin = f_data + size; @@ -5139,26 +4364,41 @@ void unit_write( } break; default: - FAIL("Not implemented",); + FAIL("Not implemented", 0); } } // ============================================================== - i64 output_size = unit_write_in_memory(pool, &codegen, &linker, unit, format, arch); + i64 output_size = unit_write_in_memory(pool, codegen, linker, unit, format, arch); + + if (output_size <= 0) + return 0; // ============================================================== // // Write the output buffer into the file - u8 *output_buffer = CHUNK(pool, linker.output_buffer, u8); - CHECK(output_buffer != NULL, "Internal",); + u8 *output_buffer = CHUNK(pool, linker->output_buffer, u8); + CHECK(output_buffer != NULL, "Internal", 0); io_write(io_out, output_size, output_buffer, io_user_data); - // ============================================================== - // - // Cleanup + return 1; +} + +b8 unit_write( + Pool * pool, + i64 unit, + u16 format, + u16 arch, + i64 io_out, + void * io_user_data +) { + Codegen_Context codegen = {0}; + Linker_Context linker = {0}; + + b8 status = unit_write_with_context(pool, &codegen, &linker, unit, format, arch, io_out, io_user_data); chunk_remove(pool, codegen.entities); chunk_remove(pool, codegen.rels); @@ -5172,6 +4412,8 @@ void unit_write( chunk_remove(pool, linker.symbols); chunk_remove(pool, linker.rels); chunk_remove(pool, linker.output_buffer); + + return status; } i64 io_open_read(i64 name_size, c8 *name, void *user_data) { @@ -5214,11 +4456,13 @@ i64 io_write(i64 f, i64 size, void *data, void *user_data) { void io_chmod_exe(i64 f, void *user_data) { dispatch_io(IO_CHMOD_EXE, &f, NULL, NULL, user_data); } + // ================================================================ // // * Helper procedures // // ================================================================ + #if HELPERS #include <stdio.h> @@ -5316,7 +4560,7 @@ void dispatch_log(i32 log_level, u32 line, c8 *file, c8 *format, ...) { // void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { - CHECK(id != NULL, "Invalid arguments",); + CHECK(id != NULL, "Sanity",); (void) user_data; @@ -5326,9 +4570,9 @@ void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { switch (op) { case IO_OPEN_READ: case IO_OPEN_WRITE: - CHECK(size != NULL, "Invalid arguments",); - CHECK(*size > 0 && *size < (i64) sizeof buf, "Invalid arguments",); - CHECK(data != NULL, "Invalid arguments",); + CHECK(size != NULL, "Sanity",); + CHECK(*size > 0 && *size < (i64) sizeof buf, "Sanity",); + CHECK(data != NULL, "Sanity",); mem_cpy(buf, data, *size); *f = fopen(buf, op == IO_OPEN_READ ? "rb" : "wb"); @@ -5338,24 +4582,24 @@ void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { break; case IO_CLOSE: - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size == NULL, "Invalid arguments",); - CHECK(data == NULL, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size == NULL, "Sanity",); + CHECK(data == NULL, "Sanity",); fclose(*f); break; case IO_SEEK: { - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size != NULL, "Invalid arguments",); - CHECK(data != NULL, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size != NULL, "Sanity",); + CHECK(data != NULL, "Sanity",); u16 *origin = (u16 *) data; if (!(*origin == IO_SEEK_CURSOR && *size == 0)) { CHECK(*origin == IO_SEEK_CURSOR || *origin == IO_SEEK_BEGIN || - *origin == IO_SEEK_END, "Invalid arguments",); + *origin == IO_SEEK_END, "Sanity",); i32 s = fseek(*f, *size, *origin == IO_SEEK_CURSOR ? SEEK_CUR : *origin == IO_SEEK_BEGIN ? SEEK_SET : @@ -5365,9 +4609,9 @@ void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { } break; case IO_TELL: { - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size != NULL, "Invalid arguments",); - CHECK(data == NULL, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size != NULL, "Sanity",); + CHECK(data == NULL, "Sanity",); i64 n = (i64) ftell(*f); CHECK(n >= 0, "File tell failed",); @@ -5376,26 +4620,26 @@ void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { } break; case IO_READ: - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size != NULL, "Invalid arguments",); - CHECK(data != NULL, "Invalid arguments",); - CHECK(*size > 0, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size != NULL, "Sanity",); + CHECK(data != NULL, "Sanity",); + CHECK(*size > 0, "Sanity",); *size = fread(data, 1, *size, *f); break; case IO_WRITE: - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size != NULL, "Invalid arguments",); - CHECK(data != NULL, "Invalid arguments",); - CHECK(*size > 0, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size != NULL, "Sanity",); + CHECK(data != NULL, "Sanity",); + CHECK(*size > 0, "Sanity",); *size = fwrite(data, 1, *size, *f); break; case IO_CHMOD_EXE: - CHECK(*f != NULL, "Invalid arguments",); - CHECK(size == NULL, "Invalid arguments",); + CHECK(*f != NULL, "Sanity",); + CHECK(size == NULL, "Sanity",); #ifdef __unix__ fchmod(fileno(*f), 0775); @@ -5403,7 +4647,7 @@ void dispatch_io(u16 op, i64 *id, i64 *size, void *data, void *user_data) { break; default: - FAIL("Invalid arguments",); + FAIL("Sanity",); } } @@ -5519,10 +4763,12 @@ void u_elf_x86_64(i64 unit, c8 *output_file_name) { i64 name_len = str_len(output_file_name, output_file_name + MAX_STRING_SIZE); i64 out = io_open_write(name_len, output_file_name, NULL); - unit_write(&g_pool, unit, FORMAT_ELF, ARCH_X86_64, out, NULL); + b8 ok = unit_write(&g_pool, unit, FORMAT_ELF, ARCH_X86_64, out, NULL); io_chmod_exe(out, NULL); io_close(out, NULL); + + CHECK(ok, "Failed",); } void l_code(i64 unit, i64 link_unit) { @@ -5605,11 +4851,13 @@ c8 *l_find(c8 *name, b8 silent) { } #endif + // ================================================================ // // TEST SUITE // // ================================================================ + #if TESTING #if HELPERS |