X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=ir.c;h=50100107b3f281c457374774202995a98358815e;hp=13afbba83781a91a53b95f028c3ea51d550d30e0;hb=3e3b8993aab022c23bb3173d7d3d1f55673a1c34;hpb=47db74c699def426f49908d470b32ee5f5e2e5df diff --git a/ir.c b/ir.c index 13afbba..5010010 100644 --- a/ir.c +++ b/ir.c @@ -83,11 +83,11 @@ uint16_t type_store_instr[TYPE_COUNT] = { INSTR_STORE_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; uint16_t field_store_instr[TYPE_COUNT] = { @@ -107,11 +107,11 @@ uint16_t field_store_instr[TYPE_COUNT] = { INSTR_STORE_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; uint16_t type_storep_instr[TYPE_COUNT] = { @@ -131,11 +131,11 @@ uint16_t type_storep_instr[TYPE_COUNT] = { INSTR_STOREP_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; uint16_t type_eq_instr[TYPE_COUNT] = { @@ -155,11 +155,11 @@ uint16_t type_eq_instr[TYPE_COUNT] = { INSTR_EQ_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; uint16_t type_ne_instr[TYPE_COUNT] = { @@ -179,11 +179,11 @@ uint16_t type_ne_instr[TYPE_COUNT] = { INSTR_NE_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; uint16_t type_not_instr[TYPE_COUNT] = { @@ -203,11 +203,11 @@ uint16_t type_not_instr[TYPE_COUNT] = { INSTR_NOT_V, /* variant, should never be accessed */ - AINSTR_END, /* struct */ - AINSTR_END, /* union */ - AINSTR_END, /* array */ - AINSTR_END, /* nil */ - AINSTR_END, /* noexpr */ + VINSTR_END, /* struct */ + VINSTR_END, /* union */ + VINSTR_END, /* array */ + VINSTR_END, /* nil */ + VINSTR_END, /* noexpr */ }; /* protos */ @@ -485,7 +485,7 @@ ir_function* ir_function_new(ir_builder* owner, int outtype) self->values = NULL; self->locals = NULL; - self->max_varargs = NULL; + self->max_varargs = 0; self->code_function_def = -1; self->allocated_locals = 0; @@ -600,6 +600,13 @@ bool ir_function_pass_peephole(ir_function *self) if (!instr_is_operation(oper->opcode)) continue; + if (OPTS_FLAG(LEGACY_VECTOR_MATHS)) { + if (oper->opcode == INSTR_MUL_VF && oper->_ops[2]->memberof == oper->_ops[1]) + continue; + if (oper->opcode == INSTR_MUL_FV && oper->_ops[1]->memberof == oper->_ops[2]) + continue; + } + value = oper->_ops[0]; /* only do it for SSA values */ @@ -873,7 +880,6 @@ ir_block* ir_block_new(ir_function* owner, const char *name) self->eid = 0; self->is_return = false; - self->run_id = 0; self->living = NULL; @@ -1258,12 +1264,13 @@ bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) bool ir_value_life_merge(ir_value *self, size_t s) { size_t i; + const size_t vs = vec_size(self->life); ir_life_entry_t *life = NULL; ir_life_entry_t *before = NULL; ir_life_entry_t new_entry; /* Find the first range >= s */ - for (i = 0; i < vec_size(self->life); ++i) + for (i = 0; i < vs; ++i) { before = life; life = &self->life[i]; @@ -1271,7 +1278,7 @@ bool ir_value_life_merge(ir_value *self, size_t s) break; } /* nothing found? append */ - if (i == vec_size(self->life)) { + if (i == vs) { ir_life_entry_t e; if (life && life->end+1 == s) { @@ -2013,89 +2020,10 @@ void ir_function_enumerate(ir_function *self) ++instruction_id; self->blocks[i]->eid = i; - self->blocks[i]->run_id = 0; ir_block_enumerate(self->blocks[i], &instruction_id); } } -static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed); -bool ir_function_calculate_liferanges(ir_function *self) -{ - size_t i, s; - bool changed; - - /* parameters live at 0 */ - for (i = 0; i < vec_size(self->params); ++i) - ir_value_life_merge(self->locals[i], 0); - - do { - self->run_id++; - changed = false; - for (i = 0; i != vec_size(self->blocks); ++i) - { - if (self->blocks[i]->is_return) - { - vec_free(self->blocks[i]->living); - if (!ir_block_life_propagate(self->blocks[i], NULL, &changed)) - return false; - } - } - } while (changed); - if (vec_size(self->blocks)) { - ir_block *block = self->blocks[0]; - for (i = 0; i < vec_size(block->living); ++i) { - ir_value *v = block->living[i]; - if (v->store != store_local) - continue; - if (v->vtype == TYPE_VECTOR) - continue; - self->flags |= IR_FLAG_HAS_UNINITIALIZED; - /* find the instruction reading from it */ - for (s = 0; s < vec_size(v->reads); ++s) { - if (v->reads[s]->eid == v->life[0].end) - break; - } - if (s < vec_size(v->reads)) { - if (irwarning(v->context, WARN_USED_UNINITIALIZED, - "variable `%s` may be used uninitialized in this function\n" - " -> %s:%i", - v->name, - v->reads[s]->context.file, v->reads[s]->context.line) - ) - { - return false; - } - continue; - } - if (v->memberof) { - ir_value *vec = v->memberof; - for (s = 0; s < vec_size(vec->reads); ++s) { - if (vec->reads[s]->eid == v->life[0].end) - break; - } - if (s < vec_size(vec->reads)) { - if (irwarning(v->context, WARN_USED_UNINITIALIZED, - "variable `%s` may be used uninitialized in this function\n" - " -> %s:%i", - v->name, - vec->reads[s]->context.file, vec->reads[s]->context.line) - ) - { - return false; - } - continue; - } - } - if (irwarning(v->context, WARN_USED_UNINITIALIZED, - "variable `%s` may be used uninitialized in this function", v->name)) - { - return false; - } - } - } - return true; -} - /* Local-value allocator * After finishing creating the liferange of all values used in a function * we can allocate their global-positions. @@ -2249,18 +2177,22 @@ bool ir_function_allocate_locals(ir_function *self) irerror(call->context, "internal error: unlocked parameter %s not found", v->name); goto error; } - ++opts_optimizationcount[OPTIM_CALL_STORES]; v->callparam = true; if (param < 8) ir_value_code_setaddr(v, OFS_PARM0 + 3*param); else { + size_t nprotos = vec_size(self->owner->extparam_protos); ir_value *ep; param -= 8; - if (vec_size(self->owner->extparam_protos) <= param) - ep = ir_gen_extparam_proto(self->owner); - else + if (nprotos > param) ep = self->owner->extparam_protos[param]; + else + { + ep = ir_gen_extparam_proto(self->owner); + while (++nprotos <= param) + ep = ir_gen_extparam_proto(self->owner); + } ir_instr_op(v->writes[0], 0, ep, true); call->params[param+8] = ep; } @@ -2385,13 +2317,13 @@ static void ir_op_read_write(int op, size_t *read, size_t *write) static bool ir_block_living_add_instr(ir_block *self, size_t eid) { - size_t i; - bool changed = false; - bool tempbool; - for (i = 0; i != vec_size(self->living); ++i) + size_t i; + const size_t vs = vec_size(self->living); + bool changed = false; + for (i = 0; i != vs; ++i) { - tempbool = ir_value_life_merge(self->living[i], eid); - changed = changed || tempbool; + if (ir_value_life_merge(self->living[i], eid)) + changed = true; } return changed; } @@ -2410,47 +2342,11 @@ static bool ir_block_living_lock(ir_block *self) return changed; } -static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed) -{ - size_t i; - - (void)changed; - - /* values which have been read in a previous iteration are now - * in the "living" array even if the previous block doesn't use them. - * So we have to remove whatever does not exist in the previous block. - * They will be re-added on-read, but the liferange merge won't cause - * a change. - for (i = 0; i < vec_size(self->living); ++i) - { - if (!vec_ir_value_find(prev->living, self->living[i], NULL)) { - vec_remove(self->living, i, 1); - --i; - } - } - */ - - /* Whatever the previous block still has in its living set - * must now be added to ours as well. - */ - for (i = 0; i < vec_size(prev->living); ++i) - { - if (vec_ir_value_find(self->living, prev->living[i], NULL)) - continue; - vec_push(self->living, prev->living[i]); - /* - irerror(self->contextt from prev: %s", self->label, prev->living[i]->_name); - */ - } - return true; -} - -static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed) +static bool ir_block_life_propagate(ir_block *self, bool *changed) { ir_instr *instr; ir_value *value; - bool tempbool; - size_t i, o, p, mem; + size_t i, o, p, mem, cnt; /* bitmasks which operands are read from or written to */ size_t read, write; char dbg_ind[16]; @@ -2458,10 +2354,16 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change dbg_ind[1] = '0'; (void)dbg_ind; - if (prev) - { - if (!ir_block_life_prop_previous(self, prev, changed)) - return false; + vec_free(self->living); + + p = vec_size(self->exits); + for (i = 0; i < p; ++i) { + ir_block *prev = self->exits[i]; + cnt = vec_size(prev->living); + for (o = 0; o < cnt; ++o) { + if (!vec_ir_value_find(self->living, prev->living[o], NULL)) + vec_push(self->living, prev->living[o]); + } } i = vec_size(self->instr); @@ -2509,23 +2411,23 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change * since this function is run multiple times. */ /* con_err( "Value only written %s\n", value->name); */ - tempbool = ir_value_life_merge(value, instr->eid); - *changed = *changed || tempbool; + if (ir_value_life_merge(value, instr->eid)) + *changed = true; } else { /* since 'living' won't contain it * anymore, merge the value, since * (A) doesn't. */ - tempbool = ir_value_life_merge(value, instr->eid); - *changed = *changed || tempbool; + if (ir_value_life_merge(value, instr->eid)) + *changed = true; /* Then remove */ vec_remove(self->living, idx, 1); } /* Removing a vector removes all members */ for (mem = 0; mem < 3; ++mem) { if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], &idx)) { - tempbool = ir_value_life_merge(value->members[mem], instr->eid); - *changed = *changed || tempbool; + if (ir_value_life_merge(value->members[mem], instr->eid)) + *changed = true; vec_remove(self->living, idx, 1); } } @@ -2537,8 +2439,8 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change break; } if (mem == 3 && vec_ir_value_find(self->living, value, &idx)) { - tempbool = ir_value_life_merge(value, instr->eid); - *changed = *changed || tempbool; + if (ir_value_life_merge(value, instr->eid)) + *changed = true; vec_remove(self->living, idx, 1); } } @@ -2554,7 +2456,7 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) *changed = true; } - else if (instr->opcode == INSTR_MUL_FV) + else if (instr->opcode == INSTR_MUL_FV || instr->opcode == INSTR_LOAD_V) { value = instr->_ops[1]; /* the float source will get an additional lifetime */ @@ -2629,25 +2531,86 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change } /* (A) */ - tempbool = ir_block_living_add_instr(self, instr->eid); - /*con_err( "living added values\n");*/ - *changed = *changed || tempbool; + if (ir_block_living_add_instr(self, instr->eid)) + *changed = true; } /* the "entry" instruction ID */ - tempbool = ir_block_living_add_instr(self, self->entry_id); - *changed = *changed || tempbool; + if (ir_block_living_add_instr(self, self->entry_id)) + *changed = true; - if (self->run_id == self->owner->run_id) - return true; + return true; +} + +bool ir_function_calculate_liferanges(ir_function *self) +{ + size_t i, s; + bool changed; - self->run_id = self->owner->run_id; + /* parameters live at 0 */ + for (i = 0; i < vec_size(self->params); ++i) + ir_value_life_merge(self->locals[i], 0); - for (i = 0; i < vec_size(self->entries); ++i) - { - ir_block *entry = self->entries[i]; - ir_block_life_propagate(entry, self, changed); - } + do { + self->run_id++; + changed = false; + i = vec_size(self->blocks); + while (i--) { + ir_block_life_propagate(self->blocks[i], &changed); + } + } while (changed); + if (vec_size(self->blocks)) { + ir_block *block = self->blocks[0]; + for (i = 0; i < vec_size(block->living); ++i) { + ir_value *v = block->living[i]; + if (v->store != store_local) + continue; + if (v->vtype == TYPE_VECTOR) + continue; + self->flags |= IR_FLAG_HAS_UNINITIALIZED; + /* find the instruction reading from it */ + for (s = 0; s < vec_size(v->reads); ++s) { + if (v->reads[s]->eid == v->life[0].end) + break; + } + if (s < vec_size(v->reads)) { + if (irwarning(v->context, WARN_USED_UNINITIALIZED, + "variable `%s` may be used uninitialized in this function\n" + " -> %s:%i", + v->name, + v->reads[s]->context.file, v->reads[s]->context.line) + ) + { + return false; + } + continue; + } + if (v->memberof) { + ir_value *vec = v->memberof; + for (s = 0; s < vec_size(vec->reads); ++s) { + if (vec->reads[s]->eid == v->life[0].end) + break; + } + if (s < vec_size(vec->reads)) { + if (irwarning(v->context, WARN_USED_UNINITIALIZED, + "variable `%s` may be used uninitialized in this function\n" + " -> %s:%i", + v->name, + vec->reads[s]->context.file, vec->reads[s]->context.line) + ) + { + return false; + } + continue; + } + } + if (irwarning(v->context, WARN_USED_UNINITIALIZED, + "variable `%s` may be used uninitialized in this function", v->name)) + { + return false; + } + } + } return true; } @@ -3107,7 +3070,7 @@ static ir_value* ir_gen_extparam_proto(ir_builder *ir) ir_value *global; char name[128]; - snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)+8)); + snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos))); global = ir_value_var(name, store_global, TYPE_VECTOR); vec_push(ir->extparam_protos, global); @@ -3194,7 +3157,7 @@ static bool gen_function_varargs_copy(ir_function *self) code_push_statement(&stmt, self->context.line); continue; } - ext = i - 8; + ext = i - 9; if (ext >= vec_size(ir->extparams)) ir_gen_extparam(ir); @@ -3218,9 +3181,12 @@ static bool gen_function_locals(ir_builder *ir, ir_value *global) irfun = global->constval.vfunc; def = code_functions + irfun->code_function_def; - if (opts.g || !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS) || (irfun->flags & IR_FLAG_MASK_NO_OVERLAP)) + if (OPTS_OPTION_BOOL(OPTION_G) || + !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS) || + (irfun->flags & IR_FLAG_MASK_NO_OVERLAP)) + { firstlocal = def->firstlocal = vec_size(code_globals); - else { + } else { firstlocal = def->firstlocal = ir->first_common_local; ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS]; } @@ -3366,7 +3332,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc def.type = global->vtype; def.offset = vec_size(code_globals); def.name = 0; - if (opts.g || !islocal) + if (OPTS_OPTION_BOOL(OPTION_G) || !islocal) { pushdef = true; @@ -3542,7 +3508,7 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) def.offset = (uint16_t)vec_size(code_globals); /* create a global named the same as the field */ - if (opts.standard == COMPILER_GMQCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) { /* in our standard, the global gets a dot prefix */ size_t len = strlen(field->name); char name[1024]; @@ -3680,7 +3646,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename) code_push_statement(&stmt, vec_last(code_linenums)); } - if (opts.pp_only) + if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) return true; if (vec_size(code_statements) != vec_size(code_linenums)) { @@ -3701,7 +3667,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename) memcpy(vec_add(lnofile, 5), ".lno", 5); } - if (!opts.quiet) { + if (!OPTS_OPTION_BOOL(OPTION_QUIET)) { if (lnofile) con_out("writing '%s' and '%s'...\n", filename, lnofile); else @@ -3853,11 +3819,8 @@ void ir_function_dump(ir_function *f, char *ind, } if (vec_size(f->blocks)) { - oprintf("%slife passes (check): %i\n", ind, (int)f->run_id); + oprintf("%slife passes: %i\n", ind, (int)f->run_id); for (i = 0; i < vec_size(f->blocks); ++i) { - if (f->blocks[i]->run_id != f->run_id) { - oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id); - } ir_block_dump(f->blocks[i], ind, oprintf); }