summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-11-25 08:55:39 +0100
committerMitya Selivanov <automainint@guattari.tech>2024-11-25 08:55:39 +0100
commit53eed017eb1260877c15f66c2d9910f118b64d29 (patch)
treef65a3f9b3ab652069edc8b6d343d7c31df4dc559
parentc75afbdcd611668e7f239dcfb4ab3846a82c0c8c (diff)
downloadbxgen-53eed017eb1260877c15f66c2d9910f118b64d29.zip
Codegen refactor
-rwxr-xr-xbxgen.c1858
1 files changed, 553 insertions, 1305 deletions
diff --git a/bxgen.c b/bxgen.c
index 6c711f8..c421436 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -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