X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ir.c;h=848e488e4d52e053b63fb33e6dbed1b11ce11685;hb=04cf1d549f7602b7b9521b12355204d3e8fd1249;hp=850f070d5e2e1ac3f767584b1868ef5a43763ae7;hpb=5ca6f4abcafcaaf0f5804111f381a97a2b0e871c;p=xonotic%2Fgmqcc.git diff --git a/ir.c b/ir.c index 850f070..848e488 100644 --- a/ir.c +++ b/ir.c @@ -34,6 +34,9 @@ ir_builder* ir_builder_new(const char *modulename) ir_builder* self; self = (ir_builder*)mem_a(sizeof(*self)); + if (!self) + return NULL; + MEM_VECTOR_INIT(self, functions); MEM_VECTOR_INIT(self, globals); self->name = NULL; @@ -140,6 +143,10 @@ ir_function* ir_function_new(ir_builder* owner) { ir_function *self; self = (ir_function*)mem_a(sizeof(*self)); + + if (!self) + return NULL; + self->name = NULL; if (!ir_function_set_name(self, "<@unnamed>")) { mem_d(self); @@ -252,6 +259,11 @@ ir_block* ir_block_new(ir_function* owner, const char *name) { ir_block *self; self = (ir_block*)mem_a(sizeof(*self)); + if (!self) + return NULL; + + memset(self, 0, sizeof(*self)); + self->label = NULL; if (!ir_block_set_label(self, name)) { mem_d(self); @@ -269,6 +281,9 @@ ir_block* ir_block_new(ir_function* owner, const char *name) self->is_return = false; self->run_id = 0; MEM_VECTOR_INIT(self, living); + + self->generated = false; + return self; } MEM_VEC_FUNCTIONS(ir_block, ir_instr*, instr) @@ -305,6 +320,9 @@ ir_instr* ir_instr_new(ir_block* owner, int op) { ir_instr *self; self = (ir_instr*)mem_a(sizeof(*self)); + if (!self) + return NULL; + self->owner = owner; self->context.file = "<@no context>"; self->context.line = 0; @@ -1762,9 +1780,168 @@ static bool gen_global_pointer(ir_value *global) return true; } +static bool gen_blocks_recursive(ir_function *func, ir_block *block) +{ + prog_section_statement stmt; + prog_section_statement *stptr; + ir_instr *instr; + ir_block *target; + ir_block *ontrue; + ir_block *onfalse; + size_t stidx; + size_t i; + +tailcall: + block->generated = true; + block->code_start = code_statements_elements; + for (i = 0; i < block->instr_count; ++i) + { + instr = block->instr[i]; + + if (instr->opcode == VINSTR_PHI) { + printf("cannot generate virtual instruction (phi)\n"); + return false; + } + + if (instr->opcode == VINSTR_JUMP) { + target = instr->bops[0]; + /* for uncoditional jumps, if the target hasn't been generated + * yet, we generate them right here. + */ + if (!target->generated) { + block = target; + goto tailcall; + } + + /* otherwise we generate a jump instruction */ + stmt.opcode = INSTR_GOTO; + stmt.o1.s1 = (target->code_start-1) - code_statements_elements; + stmt.o2.s1 = 0; + stmt.o3.s1 = 0; + if (code_statements_add(stmt) < 0) + return false; + + /* no further instructions can be in this block */ + return true; + } + + if (instr->opcode == VINSTR_COND) { + ontrue = instr->bops[0]; + onfalse = instr->bops[1]; + /* TODO: have the AST signal which block should + * come first: eg. optimize IFs without ELSE... + */ + + stmt.o1.s1 = instr->_ops[0]->code.globaladdr; + + stmt.o3.s1 = 0; + if (ontrue->generated) { + stmt.opcode = INSTR_IF; + stmt.o2.s1 = (ontrue->code_start-1) - code_statements_elements; + if (code_statements_add(stmt) < 0) + return false; + } + if (onfalse->generated) { + stmt.opcode = INSTR_IFNOT; + stmt.o2.s1 = (onfalse->code_start-1) - code_statements_elements; + if (code_statements_add(stmt) < 0) + return false; + } + if (!ontrue->generated) { + if (onfalse->generated) { + block = ontrue; + goto tailcall; + } + } + if (!onfalse->generated) { + if (ontrue->generated) { + block = onfalse; + goto tailcall; + } + } + /* neither ontrue nor onfalse exist */ + stmt.opcode = INSTR_IFNOT; + stidx = code_statements_elements - 1; + if (code_statements_add(stmt) < 0) + return false; + stptr = &code_statements_data[stidx]; + /* on false we jump, so add ontrue-path */ + if (!gen_blocks_recursive(func, ontrue)) + return false; + /* fixup the jump address */ + stptr->o2.s1 = (ontrue->code_start-1) - (stidx+1); + /* generate onfalse path */ + if (onfalse->generated) { + /* may have been generated in the previous recursive call */ + stmt.opcode = INSTR_GOTO; + stmt.o2.s1 = 0; + stmt.o3.s1 = 0; + stmt.o1.s1 = (onfalse->code_start-1) - code_statements_elements; + return (code_statements_add(stmt) >= 0); + } + /* if not, generate now */ + block = onfalse; + goto tailcall; + } + + if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) { + printf("TODO: call instruction\n"); + return false; + } + + if (instr->opcode == INSTR_STATE) { + printf("TODO: state instruction\n"); + return false; + } + + stmt.opcode = instr->opcode; + stmt.o1.u1 = 0; + stmt.o2.u1 = 0; + stmt.o3.u1 = 0; + + /* This is the general order of operands */ + if (instr->_ops[0]) + stmt.o3.u1 = instr->_ops[0]->code.globaladdr; + + if (instr->_ops[1]) + stmt.o1.u1 = instr->_ops[1]->code.globaladdr; + + if (instr->_ops[2]) + stmt.o2.u1 = instr->_ops[2]->code.globaladdr; + + if (stmt.opcode == INSTR_RETURN) + { + stmt.o1.u1 = stmt.o3.u1; + stmt.o3.u1 = 0; + } + + if (code_statements_add(stmt) < 0) + return false; + } + return true; +} + static bool gen_function_code(ir_function *self) { - return false; + ir_block *block; + + /* Starting from entry point, we generate blocks "as they come" + * for now. Dead blocks will not be translated obviously. + */ + if (!self->blocks_count) { + printf("Function '%s' declared without body.\n", self->name); + return false; + } + + block = self->blocks[0]; + if (block->generated) + return true; + + if (!gen_blocks_recursive(self, block)) { + printf("failed to generate blocks for '%s'\n", self->name); + return false; + } + return true; } static bool gen_global_function(ir_builder *ir, ir_value *global) @@ -1800,13 +1977,17 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) fun.locals = irfun->locals_count; fun.firstlocal = code_globals_elements; for (i = 0; i < irfun->locals_count; ++i) { - if (!ir_builder_gen_global(ir, irfun->locals[i])) + if (!ir_builder_gen_global(ir, irfun->locals[i])) { + printf("Failed to generate global %s\n", irfun->locals[i]->name); return false; + } } fun.entry = code_statements_elements; - if (!gen_function_code(irfun)) + if (!gen_function_code(irfun)) { + printf("Failed to generate code for function %s\n", irfun->name); return false; + } return (code_functions_add(fun) >= 0); } @@ -1816,30 +1997,25 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) int32_t *iptr; prog_section_def def; - def.type = 0; + def.type = global->vtype; def.offset = code_globals_elements; def.name = global->code.name = code_genstring(global->name); switch (global->vtype) { case TYPE_POINTER: - def.type = 7; if (code_defs_add(def) < 0) return false; return gen_global_pointer(global); case TYPE_FIELD: - def.type = 5; if (code_defs_add(def) < 0) return false; return gen_global_field(global); case TYPE_ENTITY: - def.type = 4; if (code_defs_add(def) < 0) return false; case TYPE_FLOAT: { - def.type = 2; - if (code_defs_add(def) < 0) return false; @@ -1853,7 +2029,6 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) } case TYPE_STRING: { - def.type = 1; if (code_defs_add(def) < 0) return false; if (global->isconst) @@ -1864,8 +2039,6 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) } case TYPE_VECTOR: { - def.type = 3; - if (code_defs_add(def) < 0) return false; @@ -1882,10 +2055,15 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) return global->code.globaladdr >= 0; } case TYPE_FUNCTION: - def.type = 6; if (code_defs_add(def) < 0) return false; return gen_global_function(self, global); + case TYPE_VARIANT: + /* assume biggest type */ + global->code.globaladdr = code_globals_add(0); + code_globals_add(0); + code_globals_add(0); + return true; default: /* refuse to create 'void' type or any other fancy business. */ printf("Invalid type for global variable %s\n", global->name); @@ -1909,8 +2087,8 @@ bool ir_builder_generate(ir_builder *self, const char *filename) return false; } - code_write(filename); - return false; + printf("writing '%s'...\n", filename); + return code_write(filename); } /***********************************************************************