X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ir.c;h=fb6f4e90ca330bde92f830b4590abdfa0df265c1;hb=0bee75940616ea487cf52d1ea82c9f7a90c8d4e6;hp=557a821886cd3df4488142c1ef6642e2b2427fa7;hpb=7245b675b2e4541f9fd7c9b3cb983c7d7b831c48;p=xonotic%2Fgmqcc.git diff --git a/ir.c b/ir.c index 557a821..fb6f4e9 100644 --- a/ir.c +++ b/ir.c @@ -29,6 +29,23 @@ * Type sizes used at multiple points in the IR codegen */ +const char *type_name[TYPE_COUNT] = { + "void", + "string", + "float", + "vector", + "entity", + "field", + "function", + "pointer", +#if 0 + "integer", +#endif + "quaternion", + "matrix", + "variant" +}; + size_t type_sizeof[TYPE_COUNT] = { 1, /* TYPE_VOID */ 1, /* TYPE_STRING */ @@ -41,7 +58,9 @@ size_t type_sizeof[TYPE_COUNT] = { #if 0 1, /* TYPE_INTEGER */ #endif - 3, /* TYPE_VARIANT */ + 4, /* TYPE_QUATERNION */ + 16, /* TYPE_MATRIX */ + 16, /* TYPE_VARIANT */ }; uint16_t type_store_instr[TYPE_COUNT] = { @@ -54,9 +73,30 @@ uint16_t type_store_instr[TYPE_COUNT] = { INSTR_STORE_FNC, INSTR_STORE_ENT, /* should use I */ #if 0 - INSTR_STORE_ENT, /* integer type */ + INSTR_STORE_I, /* integer type */ +#endif + INSTR_STORE_Q, + INSTR_STORE_M, + + INSTR_STORE_M, /* variant, should never be accessed */ +}; + +uint16_t type_storep_instr[TYPE_COUNT] = { + INSTR_STOREP_F, /* should use I when having integer support */ + INSTR_STOREP_S, + INSTR_STOREP_F, + INSTR_STOREP_V, + INSTR_STOREP_ENT, + INSTR_STOREP_FLD, + INSTR_STOREP_FNC, + INSTR_STOREP_ENT, /* should use I */ +#if 0 + INSTR_STOREP_ENT, /* integer type */ #endif - INSTR_STORE_V, /* variant, should never be accessed */ + INSTR_STOREP_Q, + INSTR_STOREP_M, + + INSTR_STOREP_M, /* variant, should never be accessed */ }; MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v) @@ -75,6 +115,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); @@ -90,6 +131,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) @@ -103,7 +145,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); } @@ -166,9 +212,14 @@ ir_value* ir_builder_get_global(ir_builder *self, const char *name) ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype) { - ir_value *ve = ir_builder_get_global(self, name); - if (ve) { - return NULL; + ir_value *ve; + + if (name && name[0] != '#') + { + ve = ir_builder_get_global(self, name); + if (ve) { + return NULL; + } } ve = ir_value_var(name, store_global, vtype); @@ -179,6 +230,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 */ @@ -296,14 +374,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; @@ -552,6 +637,24 @@ bool ir_value_set_vector(ir_value *self, vector v) return true; } +bool ir_value_set_quaternion(ir_value *self, quaternion v) +{ + if (self->vtype != TYPE_QUATERNION) + return false; + memcpy(&self->constval.vquat, v, sizeof(self->constval.vquat)); + self->isconst = true; + return true; +} + +bool ir_value_set_matrix(ir_value *self, matrix v) +{ + if (self->vtype != TYPE_MATRIX) + return false; + memcpy(&self->constval.vmat, v, sizeof(self->constval.vmat)); + self->isconst = true; + return true; +} + bool ir_value_set_string(ir_value *self, const char *str) { if (self->vtype != TYPE_STRING) @@ -830,46 +933,14 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what) else vtype = target->vtype; - switch (vtype) { - case TYPE_FLOAT: -#if 0 - if (what->vtype == TYPE_INTEGER) - op = INSTR_CONV_ITOF; - else -#endif - op = INSTR_STORE_F; - break; - case TYPE_VECTOR: - op = INSTR_STORE_V; - break; - case TYPE_ENTITY: - op = INSTR_STORE_ENT; - break; - case TYPE_STRING: - op = INSTR_STORE_S; - break; - case TYPE_FIELD: - op = INSTR_STORE_FLD; - break; #if 0 - case TYPE_INTEGER: - if (what->vtype == TYPE_INTEGER) - op = INSTR_CONV_FTOI; - else - op = INSTR_STORE_I; - break; + if (vtype == TYPE_FLOAT && what->vtype == TYPE_INTEGER) + op = INSTR_CONV_ITOF; + else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT) + op = INSTR_CONV_FTOI; #endif - case TYPE_POINTER: -#if 0 - op = INSTR_STORE_I; -#else - op = INSTR_STORE_ENT; -#endif - break; - default: - /* Unknown type */ - return false; - } + op = type_store_instr[vtype]; + return ir_block_create_store_op(self, op, target, what); } @@ -886,38 +957,7 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what) */ vtype = what->vtype; - switch (vtype) { - case TYPE_FLOAT: - op = INSTR_STOREP_F; - break; - case TYPE_VECTOR: - op = INSTR_STOREP_V; - break; - case TYPE_ENTITY: - op = INSTR_STOREP_ENT; - break; - case TYPE_STRING: - op = INSTR_STOREP_S; - break; - case TYPE_FIELD: - op = INSTR_STOREP_FLD; - break; -#if 0 - case TYPE_INTEGER: - op = INSTR_STOREP_I; - break; -#endif - case TYPE_POINTER: -#if 0 - op = INSTR_STOREP_I; -#else - op = INSTR_STOREP_ENT; -#endif - break; - default: - /* Unknown type */ - return false; - } + op = type_storep_instr[vtype]; return ir_block_create_store_op(self, op, target, what); } @@ -1209,6 +1249,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) { @@ -1244,6 +1317,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; @@ -1251,7 +1326,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) @@ -1275,6 +1352,8 @@ ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_va case TYPE_POINTER: op = INSTR_LOAD_I; break; case TYPE_INTEGER: op = INSTR_LOAD_I; break; #endif + case TYPE_QUATERNION: op = INSTR_LOAD_Q; break; + case TYPE_MATRIX: op = INSTR_LOAD_M; break; default: return NULL; } @@ -1378,12 +1457,22 @@ ir_value* ir_block_create_mul(ir_block *self, case TYPE_VECTOR: op = INSTR_MUL_V; break; + case TYPE_QUATERNION: + op = INSTR_MUL_Q; + break; + case TYPE_MATRIX: + op = INSTR_MUL_M; + break; } } else { if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) ) op = INSTR_MUL_VF; else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) ) op = INSTR_MUL_FV; + else if ( (l == TYPE_QUATERNION && r == TYPE_FLOAT) ) + op = INSTR_MUL_QF; + else if ( (l == TYPE_MATRIX && r == TYPE_FLOAT) ) + op = INSTR_MUL_MF; #if 0 else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) ) op = INSTR_MUL_VI; @@ -1504,7 +1593,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 @@ -1884,8 +1973,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 */ @@ -2050,21 +2142,7 @@ static bool gen_global_field(ir_value *global) } 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); + global->code.globaladdr = code_globals_add(0); } if (global->code.globaladdr < 0) return false; @@ -2263,7 +2341,7 @@ tailcall: if (code_statements_add(stmt) < 0) return false; } - return false; + continue; } if (instr->opcode == INSTR_STATE) { @@ -2291,10 +2369,8 @@ tailcall: 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; @@ -2310,6 +2386,7 @@ tailcall: static bool gen_function_code(ir_function *self) { ir_block *block; + prog_section_statement stmt; /* Starting from entry point, we generate blocks "as they come" * for now. Dead blocks will not be translated obviously. @@ -2327,6 +2404,14 @@ static bool gen_function_code(ir_function *self) printf("failed to generate blocks for '%s'\n", self->name); return false; } + + /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */ + stmt.opcode = AINSTR_END; + stmt.o1.u1 = 0; + stmt.o2.u1 = 0; + stmt.o3.u1 = 0; + if (code_statements_add(stmt) < 0) + return false; return true; } @@ -2354,10 +2439,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) for (i = 0;i < 8; ++i) { if (i >= fun.nargs) fun.argsize[i] = 0; - else if (irfun->params[i] == TYPE_VECTOR) - fun.argsize[i] = 3; else - fun.argsize[i] = 1; + fun.argsize[i] = type_sizeof[irfun->params[i]]; } fun.firstlocal = code_globals_elements; @@ -2401,6 +2484,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; @@ -2444,32 +2528,46 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global) return global->code.globaladdr >= 0; } case TYPE_VECTOR: + case TYPE_QUATERNION: + case TYPE_MATRIX: { + size_t d; if (code_defs_add(def) < 0) return false; if (global->isconst) { iptr = (int32_t*)&global->constval.vvec; global->code.globaladdr = code_globals_add(iptr[0]); - if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0) + if (global->code.globaladdr < 0) return false; + for (d = 1; d < type_sizeof[global->vtype]; ++d) + { + if (code_globals_add(iptr[d]) < 0) + return false; + } } else { global->code.globaladdr = code_globals_add(0); - if (code_globals_add(0) < 0 || code_globals_add(0) < 0) + if (global->code.globaladdr < 0) return false; + for (d = 1; d < type_sizeof[global->vtype]; ++d) + { + if (code_globals_add(0) < 0) + return false; + } } return global->code.globaladdr >= 0; } case TYPE_FUNCTION: if (code_defs_add(def) < 0) return false; + global->code.globaladdr = 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); + 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. */ @@ -2478,12 +2576,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; + + field->code.globaladdr = 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])) { @@ -2539,6 +2675,10 @@ void ir_function_dump(ir_function *f, char *ind, int (*oprintf)(const char*, ...)) { size_t i; + if (f->builtin != 0) { + oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin); + return; + } oprintf("%sfunction %s\n", ind, f->name); strncat(ind, "\t", IND_BUFSZ); if (f->locals_count) @@ -2642,6 +2782,7 @@ void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...)) { if (v->isconst) { switch (v->vtype) { + default: case TYPE_VOID: oprintf("(void)"); break;