X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=ir.c;h=d007321383bb7298f90a8c4ae3262ce481745ec8;hp=077ac555c9f42ac20de0b2bcdcfcb2e65f621c9f;hb=1559dedfd9d417d50bcbbcd809357c06b07d43b2;hpb=fe8457f9bac503fc085e63bf3d37cdb4578eef5e diff --git a/ir.c b/ir.c index 077ac55..d007321 100644 --- a/ir.c +++ b/ir.c @@ -90,6 +90,7 @@ ir_builder* ir_builder_new(const char *modulename) MEM_VECTOR_INIT(self, functions); MEM_VECTOR_INIT(self, globals); + MEM_VECTOR_INIT(self, fields); self->name = NULL; if (!ir_builder_set_name(self, modulename)) { mem_d(self); @@ -105,6 +106,7 @@ ir_builder* ir_builder_new(const char *modulename) } MEM_VEC_FUNCTIONS(ir_builder, ir_value*, globals) +MEM_VEC_FUNCTIONS(ir_builder, ir_value*, fields) MEM_VEC_FUNCTIONS(ir_builder, ir_function*, functions) void ir_builder_delete(ir_builder* self) @@ -118,7 +120,11 @@ void ir_builder_delete(ir_builder* self) for (i = 0; i != self->globals_count; ++i) { ir_value_delete(self->globals[i]); } - MEM_VECTOR_CLEAR(self, globals); + MEM_VECTOR_CLEAR(self, fields); + for (i = 0; i != self->fields_count; ++i) { + ir_value_delete(self->fields[i]); + } + MEM_VECTOR_CLEAR(self, fields); mem_d(self); } @@ -194,6 +200,33 @@ ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype return ve; } +ir_value* ir_builder_get_field(ir_builder *self, const char *name) +{ + size_t i; + for (i = 0; i < self->fields_count; ++i) { + if (!strcmp(self->fields[i]->name, name)) + return self->fields[i]; + } + return NULL; +} + + +ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype) +{ + ir_value *ve = ir_builder_get_field(self, name); + if (ve) { + return NULL; + } + + ve = ir_value_var(name, store_global, TYPE_FIELD); + ve->fieldtype = vtype; + if (!ir_builder_fields_add(self, ve)) { + ir_value_delete(ve); + return NULL; + } + return ve; +} + /*********************************************************************** *IR Function */ @@ -311,14 +344,21 @@ ir_value* ir_function_get_local(ir_function *self, const char *name) return NULL; } -ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype) +ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param) { ir_value *ve = ir_function_get_local(self, name); if (ve) { return NULL; } - ve = ir_value_var(name, store_local, vtype); + if (param && + self->locals_count && + self->locals[self->locals_count-1]->store != store_param) { + printf("cannot add parameters after adding locals\n"); + return NULL; + } + + ve = ir_value_var(name, (param ? store_param : store_local), vtype); if (!ir_function_locals_add(self, ve)) { ir_value_delete(ve); return NULL; @@ -479,6 +519,19 @@ bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) *IR Value */ +void ir_value_code_setaddr(ir_value *self, int32_t gaddr) +{ + self->code.globaladdr = gaddr; + if (self->members[0]) self->members[0]->code.globaladdr = gaddr; + if (self->members[1]) self->members[1]->code.globaladdr = gaddr; + if (self->members[2]) self->members[2]->code.globaladdr = gaddr; +} + +int32_t ir_value_code_addr(const ir_value *self) +{ + return self->code.globaladdr + self->code.addroffset; +} + ir_value* ir_value_var(const char *name, int storetype, int vtype) { ir_value *self; @@ -501,6 +554,27 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype) MEM_VECTOR_INIT(self, life); return self; } + +ir_value* ir_value_vector_member(ir_value *self, unsigned int member) +{ + ir_value *m; + if (member >= 3) + return NULL; + + if (self->members[member]) + return self->members[member]; + + m = ir_value_var(self->name, self->store, TYPE_FLOAT); + if (!m) + return NULL; + m->context = self->context; + + self->members[member] = m; + m->code.addroffset = member; + + return m; +} + MEM_VEC_FUNCTIONS(ir_value, ir_life_entry_t, life) MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, reads) MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, writes) @@ -520,6 +594,7 @@ ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int void ir_value_delete(ir_value* self) { + size_t i; if (self->name) mem_d((void*)self->name); if (self->isconst) @@ -527,6 +602,10 @@ void ir_value_delete(ir_value* self) if (self->vtype == TYPE_STRING) mem_d((void*)self->constval.vstring); } + for (i = 0; i < 3; ++i) { + if (self->members[i]) + ir_value_delete(self->members[i]); + } MEM_VECTOR_CLEAR(self, reads); MEM_VECTOR_CLEAR(self, writes); MEM_VECTOR_CLEAR(self, life); @@ -567,6 +646,15 @@ bool ir_value_set_vector(ir_value *self, vector v) return true; } +bool ir_value_set_field(ir_value *self, ir_value *fld) +{ + if (self->vtype != TYPE_FIELD) + return false; + self->constval.vpointer = fld; + self->isconst = true; + return true; +} + bool ir_value_set_string(ir_value *self, const char *str) { if (self->vtype != TYPE_STRING) @@ -1162,6 +1250,39 @@ ir_value* ir_block_create_binop(ir_block *self, return ir_block_create_general_instr(self, label, opcode, left, right, ot); } +ir_value* ir_block_create_unary(ir_block *self, + const char *label, int opcode, + ir_value *operand) +{ + int ot = TYPE_FLOAT; + switch (opcode) { + case INSTR_NOT_F: + case INSTR_NOT_V: + case INSTR_NOT_S: + case INSTR_NOT_ENT: + case INSTR_NOT_FNC: +#if 0 + case INSTR_NOT_I: +#endif + ot = TYPE_FLOAT; + break; + /* QC doesn't have other unary operations. We expect extensions to fill + * the above list, otherwise we assume out-type = in-type, eg for an + * unary minus + */ + default: + ot = operand->vtype; + break; + }; + if (ot == TYPE_VOID) { + /* The AST or parser were supposed to check this! */ + return NULL; + } + + /* let's use the general instruction creator and pass NULL for OPB */ + return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot); +} + ir_value* ir_block_create_general_instr(ir_block *self, const char *label, int op, ir_value *a, ir_value *b, int outype) { @@ -1197,6 +1318,8 @@ on_error: ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field) { + ir_value *v; + /* Support for various pointer types todo if so desired */ if (ent->vtype != TYPE_ENTITY) return NULL; @@ -1204,7 +1327,9 @@ ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_val if (field->vtype != TYPE_FIELD) return NULL; - return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER); + v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER); + v->fieldtype = field->fieldtype; + return v; } ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype) @@ -1457,7 +1582,7 @@ static bool ir_block_naive_phi(ir_block *self) if (v->writes[w]->_ops[0] == v) v->writes[w]->_ops[0] = instr->_ops[0]; - if (old->store != store_value && old->store != store_local) + if (old->store != store_value && old->store != store_local && old->store != store_param) { /* If it originally wrote to a global we need to store the value * there as welli @@ -1837,8 +1962,11 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change value = instr->_ops[o]; /* We only care about locals */ + /* we also calculate parameter liferanges so that locals + * can take up parameter slots */ if (value->store != store_value && - value->store != store_local) + value->store != store_local && + value->store != store_param) continue; /* read operands */ @@ -1999,25 +2127,11 @@ static bool gen_global_field(ir_value *global) } /* copy the field's value */ - global->code.globaladdr = code_globals_add(code_globals_data[fld->code.globaladdr]); + ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr])); } else { - prog_section_field fld; - - fld.name = global->code.name; - fld.offset = code_fields_elements; - fld.type = global->fieldtype; - - if (fld.type == TYPE_VOID) { - printf("Field is missing a type: %s\n", global->name); - return false; - } - - if (code_fields_add(fld) < 0) - return false; - - global->code.globaladdr = code_globals_add(fld.offset); + ir_value_code_setaddr(global, code_globals_add(0)); } if (global->code.globaladdr < 0) return false; @@ -2050,11 +2164,11 @@ static bool gen_global_pointer(ir_value *global) return false; } - global->code.globaladdr = code_globals_add(target->code.globaladdr); + ir_value_code_setaddr(global, code_globals_add(target->code.globaladdr)); } else { - global->code.globaladdr = code_globals_add(0); + ir_value_code_setaddr(global, code_globals_add(0)); } if (global->code.globaladdr < 0) return false; @@ -2112,7 +2226,7 @@ tailcall: * come first: eg. optimize IFs without ELSE... */ - stmt.o1.u1 = instr->_ops[0]->code.globaladdr; + stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]); stmt.o2.u1 = 0; stmt.o3.s1 = 0; @@ -2191,7 +2305,7 @@ tailcall: stmt.o3.u1 = 0; stmt.opcode = type_store_instr[param->vtype]; - stmt.o1.u1 = param->code.globaladdr; + stmt.o1.u1 = ir_value_code_addr(param); stmt.o2.u1 = OFS_PARM0 + 3 * p; if (code_statements_add(stmt) < 0) return false; @@ -2199,7 +2313,7 @@ tailcall: stmt.opcode = INSTR_CALL0 + instr->params_count; if (stmt.opcode > INSTR_CALL8) stmt.opcode = INSTR_CALL8; - stmt.o1.u1 = instr->_ops[1]->code.globaladdr; + stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]); stmt.o2.u1 = 0; stmt.o3.u1 = 0; if (code_statements_add(stmt) < 0) @@ -2211,7 +2325,7 @@ tailcall: /* not to be kept in OFS_RETURN */ stmt.opcode = type_store_instr[retvalue->vtype]; stmt.o1.u1 = OFS_RETURN; - stmt.o2.u1 = retvalue->code.globaladdr; + stmt.o2.u1 = ir_value_code_addr(retvalue); stmt.o3.u1 = 0; if (code_statements_add(stmt) < 0) return false; @@ -2231,23 +2345,21 @@ tailcall: /* This is the general order of operands */ if (instr->_ops[0]) - stmt.o3.u1 = instr->_ops[0]->code.globaladdr; + stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]); if (instr->_ops[1]) - stmt.o1.u1 = instr->_ops[1]->code.globaladdr; + stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]); if (instr->_ops[2]) - stmt.o2.u1 = instr->_ops[2]->code.globaladdr; + stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]); if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE) { stmt.o1.u1 = stmt.o3.u1; stmt.o3.u1 = 0; } - else if ((stmt.opcode >= INSTR_STORE_F && - stmt.opcode <= INSTR_STORE_FNC) || - (stmt.opcode >= INSTR_NOT_F && - stmt.opcode <= INSTR_NOT_FNC)) + else if (stmt.opcode >= INSTR_STORE_F && + stmt.opcode <= INSTR_STORE_FNC) { /* 2-operand instructions with A -> B */ stmt.o2.u1 = stmt.o3.u1; @@ -2339,7 +2451,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) { /* generate code.globaladdr for ssa values */ ir_value *v = irfun->values[i]; - v->code.globaladdr = local_var_end + v->code.local; + ir_value_code_setaddr(v, local_var_end + v->code.local); } for (i = 0; i < irfun->locals_count; ++i) { /* fill the locals with zeros */ @@ -2361,6 +2473,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) static bool ir_builder_gen_global(ir_builder *self, ir_value *global) { + size_t i; int32_t *iptr; prog_section_def def; @@ -2387,9 +2500,9 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) if (global->isconst) { iptr = (int32_t*)&global->constval.vfloat; - global->code.globaladdr = code_globals_add(*iptr); + ir_value_code_setaddr(global, code_globals_add(*iptr)); } else - global->code.globaladdr = code_globals_add(0); + ir_value_code_setaddr(global, code_globals_add(0)); return global->code.globaladdr >= 0; } @@ -2398,9 +2511,9 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) if (code_defs_add(def) < 0) return false; if (global->isconst) - global->code.globaladdr = code_globals_add(code_cachedstring(global->constval.vstring)); + ir_value_code_setaddr(global, code_globals_add(code_cachedstring(global->constval.vstring))); else - global->code.globaladdr = code_globals_add(0); + ir_value_code_setaddr(global, code_globals_add(0)); return global->code.globaladdr >= 0; } case TYPE_VECTOR: @@ -2411,7 +2524,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) if (global->isconst) { iptr = (int32_t*)&global->constval.vvec; - global->code.globaladdr = code_globals_add(iptr[0]); + ir_value_code_setaddr(global, code_globals_add(iptr[0])); if (global->code.globaladdr < 0) return false; for (d = 1; d < type_sizeof[global->vtype]; ++d) @@ -2420,7 +2533,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) return false; } } else { - global->code.globaladdr = code_globals_add(0); + ir_value_code_setaddr(global, code_globals_add(0)); if (global->code.globaladdr < 0) return false; for (d = 1; d < type_sizeof[global->vtype]; ++d) @@ -2434,14 +2547,14 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) case TYPE_FUNCTION: if (code_defs_add(def) < 0) return false; - global->code.globaladdr = code_globals_elements; + ir_value_code_setaddr(global, code_globals_elements); code_globals_add(code_functions_elements); 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); + ir_value_code_setaddr(global, code_globals_add(0)); + for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i) + code_globals_add(0); return true; default: /* refuse to create 'void' type or any other fancy business. */ @@ -2450,12 +2563,50 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) } } +static bool ir_builder_gen_field(ir_builder *self, ir_value *field) +{ + prog_section_def def; + prog_section_field fld; + + def.type = field->vtype; + def.offset = code_globals_elements; + def.name = field->code.name = code_genstring(field->name); + + if (code_defs_add(def) < 0) + return false; + + fld.name = def.name; + fld.offset = code_fields_elements; + fld.type = field->fieldtype; + + if (fld.type == TYPE_VOID) { + printf("field is missing a type: %s - don't know its size\n", field->name); + return false; + } + + if (code_fields_add(fld) < 0) + return false; + + if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype]))) + return false; + + ir_value_code_setaddr(field, code_globals_add(fld.offset)); + return field->code.globaladdr >= 0; +} + bool ir_builder_generate(ir_builder *self, const char *filename) { size_t i; code_init(); + for (i = 0; i < self->fields_count; ++i) + { + if (!ir_builder_gen_field(self, self->fields[i])) { + return false; + } + } + for (i = 0; i < self->globals_count; ++i) { if (!ir_builder_gen_global(self, self->globals[i])) {