X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ir.c;h=60d0c44704027de9728d7fac25379aed3c282710;hb=fb5a65c51aa2d99817b873c38eca52aa4e5c5a58;hp=f858bb6e9a535a63eb6233cbcac334e20af3989c;hpb=55117912abfdd387beef6a82a1281dcc18faa083;p=xonotic%2Fgmqcc.git diff --git a/ir.c b/ir.c index f858bb6..60d0c44 100644 --- a/ir.c +++ b/ir.c @@ -285,6 +285,8 @@ ir_builder* ir_builder_new(const char *modulename) self->htfields = util_htnew(IR_HT_SIZE); self->htfunctions = util_htnew(IR_HT_SIZE); + self->max_locals = 0; + self->str_immediate = 0; self->name = NULL; if (!ir_builder_set_name(self, modulename)) { @@ -433,6 +435,8 @@ ir_function* ir_function_new(ir_builder* owner, int outtype) mem_d(self); return NULL; } + self->flags = 0; + self->owner = owner; self->context.file = "<@no context>"; self->context.line = 0; @@ -605,7 +609,8 @@ bool ir_function_pass_peephole(ir_function *self) if (inot->_ops[0] != value || inot->opcode < INSTR_NOT_F || inot->opcode > INSTR_NOT_FNC || - inot->opcode == INSTR_NOT_V) /* can't do this one */ + inot->opcode == INSTR_NOT_V || /* can't do these */ + inot->opcode == INSTR_NOT_S) { break; } @@ -998,16 +1003,22 @@ 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->name) { + 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'; + } + else + name = NULL; + if (self->vtype == TYPE_VECTOR) { m = ir_value_var(name, self->store, TYPE_FLOAT); - mem_d(name); + if (name) + mem_d(name); if (!m) return NULL; m->context = self->context; @@ -1020,7 +1031,8 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member) if (self->fieldtype != TYPE_VECTOR) return NULL; m = ir_value_var(name, self->store, TYPE_FIELD); - mem_d(name); + if (name) + mem_d(name); if (!m) return NULL; m->fieldtype = TYPE_FLOAT; @@ -1522,20 +1534,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 (!ir_check_unreachable(self)) - return false; - self->final = true; - in = ir_instr_new(ctx, self, INSTR_GOTO); - if (!in) - return false; - - in->bops[0] = to; - vec_push(self->instr, in); - - vec_push(self->exits, to); - vec_push(to->entries, self); - return true; + self->owner->flags |= IR_FLAG_HAS_GOTO; + return ir_block_create_jump(self, ctx, to); } ir_instr* ir_block_create_phi(ir_block *self, lex_ctx ctx, const char *label, int ot) @@ -2225,6 +2225,7 @@ bool ir_function_calculate_liferanges(ir_function *self) if (!vec_ir_value_find(block->living, v->memberof, NULL)) continue; } + self->flags |= IR_FLAG_HAS_UNINITIALIZED; if (irwarning(v->context, WARN_USED_UNINITIALIZED, "variable `%s` may be used uninitialized in this function", v->name)) { @@ -2291,9 +2292,7 @@ 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; @@ -2499,22 +2498,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change { --i; instr = self->instr[i]; - /* PHI operands are always read operands */ - for (p = 0; p < vec_size(instr->phi); ++p) - { - value = instr->phi[p].value; - if (!vec_ir_value_find(self->living, value, NULL)) - vec_push(self->living, value); - } - - /* call params are read operands too */ - for (p = 0; p < vec_size(instr->params); ++p) - { - value = instr->params[p]; - if (!vec_ir_value_find(self->living, value, NULL)) - vec_push(self->living, value); - } - /* See which operands are read and write operands */ ir_op_read_write(instr->opcode, &read, &write); @@ -2531,7 +2514,9 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change *changed = *changed || tempbool; } - /* Go through the 3 main operands */ + /* Go through the 3 main operands + * writes first, then reads + */ for (o = 0; o < 3; ++o) { if (!instr->_ops[o]) /* no such operand */ @@ -2547,13 +2532,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change value->store != store_param) continue; - /* read operands */ - if (read & (1<living, value, NULL)) - vec_push(self->living, value); - } - /* write operands */ /* When we write to a local, we consider it "dead" for the * remaining upper part of the function, since in SSA a value @@ -2596,6 +2574,45 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change } } } + + for (o = 0; o < 3; ++o) + { + if (!instr->_ops[o]) /* no such operand */ + continue; + + 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_param) + continue; + + /* read operands */ + if (read & (1<living, value, NULL)) + vec_push(self->living, value); + } + } + /* PHI operands are always read operands */ + for (p = 0; p < vec_size(instr->phi); ++p) + { + value = instr->phi[p].value; + if (!vec_ir_value_find(self->living, value, NULL)) + vec_push(self->living, value); + } + + /* call params are read operands too */ + for (p = 0; p < vec_size(instr->params); ++p) + { + value = instr->params[p]; + if (!vec_ir_value_find(self->living, value, NULL)) + vec_push(self->living, value); + } + /* (A) */ tempbool = ir_block_living_add_instr(self, instr->eid); /*con_err( "living added values\n");*/ @@ -2632,7 +2649,7 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change * * Breaking conventions is annoying... */ -static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal); +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal, bool defs_only); static bool gen_global_field(ir_value *global) { @@ -3055,24 +3072,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global) fun.argsize[i] = type_sizeof_[irfun->params[i]]; } - fun.firstlocal = vec_size(code_globals); - - fun.locals = irfun->allocated_locals; - 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; - } - ir_value_code_setaddr(irfun->locals[i], fun.firstlocal + irfun->locals[i]->code.local); - } - 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); - } - for (i = vec_size(code_globals); i < fun.firstlocal + irfun->allocated_locals; ++i) - vec_push(code_globals, 0); + fun.firstlocal = 0; + fun.locals = irfun->allocated_locals; if (irfun->builtin) fun.entry = irfun->builtin+1; @@ -3142,6 +3143,40 @@ static bool gen_function_extparam_copy(ir_function *self) return true; } +static bool gen_function_locals(ir_builder *ir, ir_value *global) +{ + prog_section_function *def; + ir_function *irfun; + size_t i; + uint32_t firstlocal; + + 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)) + firstlocal = def->firstlocal = vec_size(code_globals); + else { + firstlocal = def->firstlocal = ir->first_common_local; + ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS]; + } + + for (i = vec_size(code_globals); i < firstlocal + irfun->allocated_locals; ++i) + vec_push(code_globals, 0); + for (i = 0; i < vec_size(irfun->locals); ++i) { + ir_value_code_setaddr(irfun->locals[i], firstlocal + irfun->locals[i]->code.local); + if (!ir_builder_gen_global(ir, irfun->locals[i], true, true)) { + irerror(irfun->locals[i]->context, "failed to generate local %s", irfun->locals[i]->name); + return false; + } + } + for (i = 0; i < vec_size(irfun->values); ++i) + { + ir_value *v = irfun->values[i]; + ir_value_code_setaddr(v, firstlocal + v->code.local); + } + return true; +} + static bool gen_global_function_code(ir_builder *ir, ir_value *global) { prog_section_function *fundef; @@ -3169,6 +3204,10 @@ static bool gen_global_function_code(ir_builder *ir, ir_value *global) fundef = &code_functions[irfun->code_function_def]; fundef->entry = vec_size(code_statements); + if (!gen_function_locals(ir, global)) { + irerror(irfun->context, "Failed to generate locals for function %s", irfun->name); + return false; + } if (!gen_function_extparam_copy(irfun)) { irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name); return false; @@ -3236,26 +3275,42 @@ static void gen_vector_fields(prog_section_field fld, const char *name) } } -static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal) +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal, bool defs_only) { size_t i; int32_t *iptr; prog_section_def def; + bool pushdef = false; - def.type = global->vtype; - def.offset = vec_size(code_globals); - - if (global->name) { - if (global->name[0] == '#') { - if (!self->str_immediate) - self->str_immediate = code_genstring("IMMEDIATE"); - def.name = global->code.name = self->str_immediate; + if (opts.g || !islocal) + { + pushdef = true; + def.type = global->vtype; + def.offset = vec_size(code_globals); + + if (global->name) { + if (global->name[0] == '#') { + if (!self->str_immediate) + self->str_immediate = code_genstring("IMMEDIATE"); + def.name = global->code.name = self->str_immediate; + } + else + def.name = global->code.name = code_genstring(global->name); } else - def.name = global->code.name = code_genstring(global->name); + def.name = 0; + if (defs_only) { + def.offset = ir_value_code_addr(global); + vec_push(code_defs, def); + if (global->vtype == TYPE_VECTOR) + gen_vector_defs(def, global->name); + else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR) + gen_vector_defs(def, global->name); + return true; + } } - else - def.name = 0; + if (defs_only) + return true; switch (global->vtype) { @@ -3280,14 +3335,17 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc ir_value_code_setaddr(global, vec_size(code_globals)); vec_push(code_globals, 0); /* Add the def */ - vec_push(code_defs, def); + if (pushdef) vec_push(code_defs, def); return true; case TYPE_POINTER: - vec_push(code_defs, def); + if (pushdef) vec_push(code_defs, def); return gen_global_pointer(global); case TYPE_FIELD: - vec_push(code_defs, def); - gen_vector_defs(def, global->name); + if (pushdef) { + vec_push(code_defs, def); + if (global->fieldtype == TYPE_VECTOR) + gen_vector_defs(def, global->name); + } return gen_global_field(global); case TYPE_ENTITY: /* fall through */ @@ -3302,7 +3360,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - vec_push(code_defs, def); + if (pushdef) vec_push(code_defs, def); return global->code.globaladdr >= 0; } @@ -3316,7 +3374,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - vec_push(code_defs, def); + if (pushdef) vec_push(code_defs, def); return global->code.globaladdr >= 0; } case TYPE_VECTOR: @@ -3342,9 +3400,11 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - vec_push(code_defs, def); - def.type &= ~DEF_SAVEGLOBAL; - gen_vector_defs(def, global->name); + if (pushdef) { + vec_push(code_defs, def); + def.type &= ~DEF_SAVEGLOBAL; + gen_vector_defs(def, global->name); + } return global->code.globaladdr >= 0; } case TYPE_FUNCTION: @@ -3360,7 +3420,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - vec_push(code_defs, def); + if (pushdef) vec_push(code_defs, def); return true; case TYPE_VARIANT: /* assume biggest type */ @@ -3456,7 +3516,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename) { prog_section_statement stmt; size_t i; - char *lnofile = NULL; + char *lnofile = NULL; code_init(); @@ -3467,9 +3527,17 @@ bool ir_builder_generate(ir_builder *self, const char *filename) for (i = 0; i < vec_size(self->globals); ++i) { - if (!ir_builder_gen_global(self, self->globals[i], false)) { + if (!ir_builder_gen_global(self, self->globals[i], false, false)) { return false; } + if (self->globals[i]->vtype == TYPE_FUNCTION) { + ir_function *func = self->globals[i]->constval.vfunc; + if (func && self->max_locals < func->allocated_locals && + !(func->flags & IR_FLAG_MASK_NO_OVERLAP)) + { + self->max_locals = func->allocated_locals; + } + } } for (i = 0; i < vec_size(self->fields); ++i) @@ -3479,6 +3547,12 @@ bool ir_builder_generate(ir_builder *self, const char *filename) } } + /* generate common locals */ + self->first_common_local = vec_size(code_globals); + for (i = 0; i < self->max_locals; ++i) { + vec_push(code_globals, 0); + } + /* generate function code */ for (i = 0; i < vec_size(self->globals); ++i) {