X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ir.c;h=12f9a5115c4e14dfad82917cb8ae0dd92fe47868;hb=7cf0ba5aa88bf09c2a91690dce29721ba7147b65;hp=2375d55368c40d0d52c5e194f70f39a1439622b2;hpb=dccafd65ac55b806b5f6e7232de5f184d8403b2d;p=xonotic%2Fgmqcc.git diff --git a/ir.c b/ir.c index 2375d55..12f9a51 100644 --- a/ir.c +++ b/ir.c @@ -45,7 +45,7 @@ const char *type_name[TYPE_COUNT] = { "array" }; -size_t type_sizeof[TYPE_COUNT] = { +size_t type_sizeof_[TYPE_COUNT] = { 1, /* TYPE_VOID */ 1, /* TYPE_STRING */ 1, /* TYPE_FLOAT */ @@ -527,7 +527,8 @@ static bool instr_is_operation(uint16_t op) (op >= INSTR_LOAD_F && op <= INSTR_LOAD_FNC) || (op == INSTR_ADDRESS) || (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) || - (op >= INSTR_AND && op <= INSTR_BITOR) ); + (op >= INSTR_AND && op <= INSTR_BITOR) || + (op >= INSTR_CALL0 && op <= INSTR_CALL8) ); } bool ir_function_pass_peephole(ir_function *self) @@ -638,7 +639,7 @@ bool ir_function_pass_peephole(ir_function *self) return true; } -bool ir_function_pass_tailcall(ir_function *self) +bool ir_function_pass_tailrecursion(ir_function *self) { size_t b, p; @@ -738,8 +739,8 @@ bool ir_function_finalize(ir_function *self) } if (OPTS_OPTIMIZATION(OPTIM_TAIL_RECURSION)) { - if (!ir_function_pass_tailcall(self)) { - irerror(self->context, "tailcall optimization pass broke something in `%s`", self->name); + if (!ir_function_pass_tailrecursion(self)) { + irerror(self->context, "tail-recursion optimization pass broke something in `%s`", self->name); return false; } } @@ -988,6 +989,8 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype) ir_value* ir_value_vector_member(ir_value *self, unsigned int member) { + char *name; + size_t len; ir_value *m; if (member >= 3) return NULL; @@ -995,9 +998,16 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member) if (self->members[member]) return self->members[member]; + len = strlen(self->name); + name = (char*)mem_a(len + 3); + memcpy(name, self->name, len); + name[len+0] = '_'; + name[len+1] = 'x' + member; + name[len+2] = '\0'; if (self->vtype == TYPE_VECTOR) { - m = ir_value_var(self->name, self->store, TYPE_FLOAT); + m = ir_value_var(name, self->store, TYPE_FLOAT); + mem_d(name); if (!m) return NULL; m->context = self->context; @@ -1009,7 +1019,8 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member) { if (self->fieldtype != TYPE_VECTOR) return NULL; - m = ir_value_var(self->name, self->store, TYPE_FIELD); + m = ir_value_var(name, self->store, TYPE_FIELD); + mem_d(name); if (!m) return NULL; m->fieldtype = TYPE_FLOAT; @@ -1028,6 +1039,13 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member) return m; } +static GMQCC_INLINE size_t ir_value_sizeof(const ir_value *self) +{ + if (self->vtype == TYPE_FIELD && self->fieldtype == TYPE_VECTOR) + return type_sizeof_[TYPE_VECTOR]; + return type_sizeof_[self->vtype]; +} + ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) { ir_value *v = ir_value_var(name, storetype, vtype); @@ -1350,15 +1368,19 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b) *IR main operations */ +static bool ir_check_unreachable(ir_block *self) +{ + /* The IR should never have to deal with unreachable code */ + if (!self->final/* || OPTS_FLAG(ALLOW_UNREACHABLE_CODE)*/) + return true; + irerror(self->context, "unreachable statement (%s)", self->label); + return false; +} + bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *target, ir_value *what) { ir_instr *in; - if (self->final) { - irerror(self->context, "unreachable statement (%s)", self->label); - return false; - } - in = ir_instr_new(ctx, self, op); - if (!in) + if (!ir_check_unreachable(self)) return false; if (target->store == store_value && @@ -1370,9 +1392,14 @@ bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *tar return false; } + in = ir_instr_new(ctx, self, op); + if (!in) + return false; + if (!ir_instr_op(in, 0, target, true) || !ir_instr_op(in, 1, what, false)) { + ir_instr_delete(in); return false; } vec_push(self->instr, in); @@ -1429,18 +1456,18 @@ bool ir_block_create_storep(ir_block *self, lex_ctx ctx, ir_value *target, ir_va bool ir_block_create_return(ir_block *self, lex_ctx ctx, ir_value *v) { ir_instr *in; - if (self->final) { - irerror(self->context, "unreachable statement (%s)", self->label); + if (!ir_check_unreachable(self)) return false; - } self->final = true; self->is_return = true; in = ir_instr_new(ctx, self, INSTR_RETURN); if (!in) return false; - if (v && !ir_instr_op(in, 0, v, false)) + if (v && !ir_instr_op(in, 0, v, false)) { + ir_instr_delete(in); return false; + } vec_push(self->instr, in); return true; @@ -1450,10 +1477,8 @@ bool ir_block_create_if(ir_block *self, lex_ctx ctx, ir_value *v, ir_block *ontrue, ir_block *onfalse) { ir_instr *in; - if (self->final) { - irerror(self->context, "unreachable statement (%s)", self->label); + if (!ir_check_unreachable(self)) return false; - } self->final = true; /*in = ir_instr_new(ctx, self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/ in = ir_instr_new(ctx, self, VINSTR_COND); @@ -1480,10 +1505,8 @@ bool ir_block_create_if(ir_block *self, lex_ctx ctx, ir_value *v, bool ir_block_create_jump(ir_block *self, lex_ctx ctx, ir_block *to) { ir_instr *in; - if (self->final) { - irerror(self->context, "unreachable statement (%s)", self->label); + if (!ir_check_unreachable(self)) return false; - } self->final = true; in = ir_instr_new(ctx, self, VINSTR_JUMP); if (!in) @@ -1500,10 +1523,8 @@ bool ir_block_create_jump(ir_block *self, lex_ctx ctx, ir_block *to) bool ir_block_create_goto(ir_block *self, lex_ctx ctx, ir_block *to) { ir_instr *in; - if (self->final) { - irerror(self->context, "unreachable statement (%s)", self->label); + if (!ir_check_unreachable(self)) return false; - } self->final = true; in = ir_instr_new(ctx, self, INSTR_GOTO); if (!in) @@ -1521,6 +1542,8 @@ ir_instr* ir_block_create_phi(ir_block *self, lex_ctx ctx, const char *label, in { ir_value *out; ir_instr *in; + if (!ir_check_unreachable(self)) + return false; in = ir_instr_new(ctx, self, VINSTR_PHI); if (!in) return NULL; @@ -1562,13 +1585,19 @@ void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v) } /* call related code */ -ir_instr* ir_block_create_call(ir_block *self, lex_ctx ctx, const char *label, ir_value *func) +ir_instr* ir_block_create_call(ir_block *self, lex_ctx ctx, const char *label, ir_value *func, bool noreturn) { ir_value *out; ir_instr *in; - in = ir_instr_new(ctx, self, INSTR_CALL0); + if (!ir_check_unreachable(self)) + return false; + in = ir_instr_new(ctx, self, (noreturn ? VINSTR_NRCALL : INSTR_CALL0)); if (!in) return NULL; + if (noreturn) { + self->final = true; + self->is_return = true; + } out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype); if (!out) { ir_instr_delete(in); @@ -1582,6 +1611,15 @@ ir_instr* ir_block_create_call(ir_block *self, lex_ctx ctx, const char *label, i return NULL; } vec_push(self->instr, in); + /* + if (noreturn) { + if (!ir_block_create_return(self, ctx, NULL)) { + compile_error(ctx, "internal error: failed to generate dummy-return instruction"); + ir_instr_delete(in); + return NULL; + } + } + */ return in; } @@ -2169,8 +2207,24 @@ bool ir_function_calculate_liferanges(ir_function *self) ir_block *block = self->blocks[0]; for (i = 0; i < vec_size(block->living); ++i) { ir_value *v = block->living[i]; - if (v->memberof || v->store != store_local) + if (v->store != store_local) continue; + if ((v->members[0] && v->members[1] && v->members[2])) { + /* all vector members have been accessed - only treat this as uninitialized + * if any of them is also uninitialized. + */ + if (!vec_ir_value_find(block->living, v->members[0], NULL) && + !vec_ir_value_find(block->living, v->members[1], NULL) && + !vec_ir_value_find(block->living, v->members[2], NULL)) + { + continue; + } + } + if (v->memberof) { + /* A member is only uninitialized if the whole vector is also uninitialized */ + if (!vec_ir_value_find(block->living, v->memberof, NULL)) + continue; + } if (irwarning(v->context, WARN_USED_UNINITIALIZED, "variable `%s` may be used uninitialized in this function", v->name)) { @@ -2196,7 +2250,7 @@ typedef struct { static bool function_allocator_alloc(function_allocator *alloc, const ir_value *var) { ir_value *slot; - size_t vsize = type_sizeof[var->vtype]; + size_t vsize = ir_value_sizeof(var); slot = ir_value_var("reg", store_global, var->vtype); if (!slot) @@ -2237,7 +2291,9 @@ bool ir_function_allocate_locals(ir_function *self) for (i = 0; i < vec_size(self->locals); ++i) { +#if 0 if (!OPTS_OPTIMIZATION(OPTIM_LOCALTEMPS)) +#endif self->locals[i]->unique_life = true; if (!function_allocator_alloc(&alloc, self->locals[i])) goto error; @@ -2263,7 +2319,7 @@ bool ir_function_allocate_locals(ir_function *self) * will be required later when overlapping temps + locals */ if (a < vec_size(self->params) && - alloc.sizes[a] < type_sizeof[v->vtype]) + alloc.sizes[a] < ir_value_sizeof(v)) { continue; } @@ -2275,8 +2331,8 @@ bool ir_function_allocate_locals(ir_function *self) goto error; /* adjust size for this slot */ - if (alloc.sizes[a] < type_sizeof[v->vtype]) - alloc.sizes[a] = type_sizeof[v->vtype]; + if (alloc.sizes[a] < ir_value_sizeof(v)) + alloc.sizes[a] = ir_value_sizeof(v); self->values[i]->code.local = a; break; @@ -2323,6 +2379,7 @@ error: cleanup: for (i = 0; i < vec_size(alloc.locals); ++i) ir_value_delete(alloc.locals[i]); + vec_free(alloc.unique); vec_free(alloc.locals); vec_free(alloc.sizes); vec_free(alloc.positions); @@ -2446,8 +2503,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change for (p = 0; p < vec_size(instr->phi); ++p) { value = instr->phi[p].value; - if (value->memberof) - value = value->memberof; if (!vec_ir_value_find(self->living, value, NULL)) vec_push(self->living, value); } @@ -2456,8 +2511,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change for (p = 0; p < vec_size(instr->params); ++p) { value = instr->params[p]; - if (value->memberof) - value = value->memberof; if (!vec_ir_value_find(self->living, value, NULL)) vec_push(self->living, value); } @@ -2485,8 +2538,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change continue; value = instr->_ops[o]; - if (value->memberof) - value = value->memberof; /* We only care about locals */ /* we also calculate parameter liferanges so that locals @@ -2789,7 +2840,9 @@ tailcall: goto tailcall; } - if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) { + if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) + || instr->opcode == VINSTR_NRCALL) + { /* Trivial call translation: * copy all params to OFS_PARM* * if the output's storetype is not store_return, @@ -2858,11 +2911,11 @@ tailcall: code_push_statement(&stmt, instr->context.line); retvalue = instr->_ops[0]; - if (retvalue && retvalue->store != store_return && vec_size(retvalue->life)) + if (retvalue && retvalue->store != store_return && (vec_size(retvalue->life) || retvalue->store == store_global)) { /* not to be kept in OFS_RETURN */ - if (retvalue->vtype == TYPE_FIELD) - stmt.opcode = field_store_instr[retvalue->vtype]; + if (retvalue->vtype == TYPE_FIELD && OPTS_FLAG(ADJUST_VECTOR_FIELDS)) + stmt.opcode = field_store_instr[retvalue->fieldtype]; else stmt.opcode = type_store_instr[retvalue->vtype]; stmt.o1.u1 = OFS_RETURN; @@ -2979,9 +3032,6 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) ir_function *irfun; size_t i; -#ifndef NEW_ALLOC_STRAT - size_t local_var_end; -#endif if (!global->hasvalue || (!global->constval.vfunc)) { @@ -3002,40 +3052,11 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) if ((int32_t)i >= fun.nargs) fun.argsize[i] = 0; else - fun.argsize[i] = type_sizeof[irfun->params[i]]; + fun.argsize[i] = type_sizeof_[irfun->params[i]]; } fun.firstlocal = vec_size(code_globals); -#ifndef NEW_ALLOC_STRAT - local_var_end = fun.firstlocal; - for (i = 0; i < vec_size(irfun->locals); ++i) { - if (!ir_builder_gen_global(ir, irfun->locals[i], true)) { - irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name); - return false; - } - } - if (vec_size(irfun->locals)) { - ir_value *last = vec_last(irfun->locals); - local_var_end = last->code.globaladdr; - if (last->vtype == TYPE_FIELD && last->fieldtype == TYPE_VECTOR) - local_var_end += type_sizeof[TYPE_VECTOR]; - else - local_var_end += type_sizeof[last->vtype]; - } - for (i = 0; i < vec_size(irfun->values); ++i) - { - /* generate code.globaladdr for ssa values */ - ir_value *v = irfun->values[i]; - ir_value_code_setaddr(v, local_var_end + v->code.local); - } - for (i = 0; i < irfun->allocated_locals; ++i) { - /* fill the locals with zeros */ - vec_push(code_globals, 0); - } - - fun.locals = vec_size(code_globals) - fun.firstlocal; -#else fun.locals = irfun->allocated_locals; for (i = 0; i < vec_size(irfun->locals); ++i) { if (!ir_builder_gen_global(ir, irfun->locals[i], true)) { @@ -3044,16 +3065,14 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) } ir_value_code_setaddr(irfun->locals[i], fun.firstlocal + irfun->locals[i]->code.local); } - for (i = vec_size(code_globals) - fun.firstlocal; i < fun.locals; ++i) { - vec_push(code_globals, 0); - } for (i = 0; i < vec_size(irfun->values); ++i) { /* generate code.globaladdr for ssa values */ ir_value *v = irfun->values[i]; ir_value_code_setaddr(v, fun.firstlocal + v->code.local); } -#endif + for (i = vec_size(code_globals); i < fun.firstlocal + irfun->allocated_locals; ++i) + vec_push(code_globals, 0); if (irfun->builtin) fun.entry = irfun->builtin+1; @@ -3309,14 +3328,14 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc vec_push(code_globals, iptr[0]); if (global->code.globaladdr < 0) return false; - for (d = 1; d < type_sizeof[global->vtype]; ++d) { + for (d = 1; d < type_sizeof_[global->vtype]; ++d) { vec_push(code_globals, iptr[d]); } } else { vec_push(code_globals, 0); if (global->code.globaladdr < 0) return false; - for (d = 1; d < type_sizeof[global->vtype]; ++d) { + for (d = 1; d < type_sizeof_[global->vtype]; ++d) { vec_push(code_globals, 0); } } @@ -3347,7 +3366,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc /* assume biggest type */ ir_value_code_setaddr(global, vec_size(code_globals)); vec_push(code_globals, 0); - for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i) + for (i = 1; i < type_sizeof_[TYPE_VARIANT]; ++i) vec_push(code_globals, 0); return true; default: @@ -3360,7 +3379,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc static void ir_builder_prepare_field(ir_value *field) { - field->code.fieldaddr = code_alloc_field(type_sizeof[field->fieldtype]); + field->code.fieldaddr = code_alloc_field(type_sizeof_[field->fieldtype]); } static bool ir_builder_gen_field(ir_builder *self, ir_value *field) @@ -3524,8 +3543,8 @@ bool ir_builder_generate(ir_builder *self, const char *filename) #define IND_BUFSZ 1024 -#ifdef WIN32 -# define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE) +#ifdef _MSC_VER +# define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE) #endif const char *qc_opname(int op) @@ -3659,7 +3678,7 @@ void ir_instr_dump(ir_instr *in, char *ind, if (in->_ops[1] || in->_ops[2]) oprintf(" <- "); } - if (in->opcode == INSTR_CALL0) { + if (in->opcode == INSTR_CALL0 || in->opcode == VINSTR_NRCALL) { oprintf("CALL%i\t", vec_size(in->params)); } else oprintf("%s\t", qc_opname(in->opcode));