X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ir.c;h=5fde1bad5b466db162ee01d218112d36bb77cc5d;hb=cf676443cb122c5b583d601fd4874d14a8e84528;hp=6081b5545bc049ef78b105a0fdd1275d1dab8ad1;hpb=24f3098418003271b26b6f0f1ba6e8411fa6e672;p=xonotic%2Fgmqcc.git diff --git a/ir.c b/ir.c index 6081b55..5fde1ba 100644 --- a/ir.c +++ b/ir.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 + * Copyright (C) 2012, 2013 * Wolfgang Bumiller * * Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -42,7 +42,10 @@ const char *type_name[TYPE_COUNT] = { "variant", "struct", "union", - "array" + "array", + + "nil", + "" }; size_t type_sizeof_[TYPE_COUNT] = { @@ -59,6 +62,8 @@ size_t type_sizeof_[TYPE_COUNT] = { 0, /* TYPE_STRUCT */ 0, /* TYPE_UNION */ 0, /* TYPE_ARRAY */ + 0, /* TYPE_NIL */ + 0, /* TYPE_NOESPR */ }; uint16_t type_store_instr[TYPE_COUNT] = { @@ -81,6 +86,8 @@ uint16_t type_store_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; uint16_t field_store_instr[TYPE_COUNT] = { @@ -103,6 +110,8 @@ uint16_t field_store_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; uint16_t type_storep_instr[TYPE_COUNT] = { @@ -125,6 +134,8 @@ uint16_t type_storep_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; uint16_t type_eq_instr[TYPE_COUNT] = { @@ -147,6 +158,8 @@ uint16_t type_eq_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; uint16_t type_ne_instr[TYPE_COUNT] = { @@ -169,6 +182,8 @@ uint16_t type_ne_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; uint16_t type_not_instr[TYPE_COUNT] = { @@ -191,6 +206,8 @@ uint16_t type_not_instr[TYPE_COUNT] = { AINSTR_END, /* struct */ AINSTR_END, /* union */ AINSTR_END, /* array */ + AINSTR_END, /* nil */ + AINSTR_END, /* noexpr */ }; /* protos */ @@ -300,6 +317,9 @@ ir_builder* ir_builder_new(const char *modulename) return NULL; } + self->nil = ir_value_var("nil", store_value, TYPE_NIL); + self->nil->cvq = CV_CONST; + return self; } @@ -325,6 +345,7 @@ void ir_builder_delete(ir_builder* self) for (i = 0; i != vec_size(self->fields); ++i) { ir_value_delete(self->fields[i]); } + ir_value_delete(self->nil); vec_free(self->fields); vec_free(self->filenames); vec_free(self->filestrings); @@ -759,8 +780,10 @@ bool ir_function_finalize(ir_function *self) } } - if (!ir_function_naive_phi(self)) + if (!ir_function_naive_phi(self)) { + irerror(self->context, "internal error: ir_function_naive_phi failed"); return false; + } for (i = 0; i < vec_size(self->locals); ++i) { ir_value *v = self->locals[i]; @@ -1890,26 +1913,6 @@ bool ir_function_naive_phi(ir_function *self) return true; } -#if 0 -static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what) -{ - ir_instr *instr; - size_t i; - - /* create a store */ - if (!ir_block_create_store(block, old, what)) - return false; - - /* we now move it up */ - instr = vec_last(block->instr); - for (i = vec_size(block->instr)-1; i > iid; --i) - block->instr[i] = block->instr[i-1]; - block->instr[i] = instr; - - return true; -} -#endif - static bool ir_block_naive_phi(ir_block *self) { size_t i, p; /*, w;*/ @@ -1952,58 +1955,6 @@ static bool ir_block_naive_phi(ir_block *self) vec_push(b->instr, prevjump); b->final = true; } - -#if 0 - ir_value *v = instr->phi[p].value; - for (w = 0; w < vec_size(v->writes); ++w) { - ir_value *old; - - if (!v->writes[w]->_ops[0]) - continue; - - /* When the write was to a global, we have to emit a mov */ - old = v->writes[w]->_ops[0]; - - /* The original instruction now writes to the PHI target local */ - if (v->writes[w]->_ops[0] == v) - v->writes[w]->_ops[0] = instr->_ops[0]; - - 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 - */ - if (!ir_naive_phi_emit_store(self, i+1, old, v)) - return false; - if (i+1 < vec_size(self->instr)) - instr = self->instr[i+1]; - else - instr = NULL; - /* In case I forget and access instr later, it'll be NULL - * when it's a problem, to make sure we crash, rather than accessing - * invalid data. - */ - } - else - { - /* If it didn't, we can replace all reads by the phi target now. */ - size_t r; - for (r = 0; r < vec_size(old->reads); ++r) - { - size_t op; - ir_instr *ri = old->reads[r]; - for (op = 0; op < vec_size(ri->phi); ++op) { - if (ri->phi[op].value == old) - ri->phi[op].value = v; - } - for (op = 0; op < 3; ++op) { - if (ri->_ops[op] == old) - ri->_ops[op] = v; - } - } - } - } -#endif } ir_instr_delete(instr); } @@ -2040,9 +1991,14 @@ static void ir_block_enumerate(ir_block *self, size_t *_eid) void ir_function_enumerate(ir_function *self) { size_t i; - size_t instruction_id = 1; + size_t instruction_id = 0; for (i = 0; i < vec_size(self->blocks); ++i) { + /* each block now gets an additional "entry" instruction id + * we can use to avoid point-life issues + */ + ++instruction_id; + self->blocks[i]->eid = i; self->blocks[i]->run_id = 0; ir_block_enumerate(self->blocks[i], &instruction_id); @@ -2169,6 +2125,9 @@ static bool ir_function_allocator_assign(ir_function *self, function_allocator * size_t a; ir_value *slot; + if (v->unique_life) + return function_allocator_alloc(alloc, v); + for (a = 0; a < vec_size(alloc->locals); ++a) { /* if it's reserved for a unique liferange: skip */ @@ -2240,7 +2199,7 @@ bool ir_function_allocate_locals(ir_function *self) break; else v->locked = true; /* lock parameters locals */ - if (!function_allocator_alloc((v->locked || !opt_gt ? &lockalloc : &globalloc), self->locals[i])) + if (!function_allocator_alloc((v->locked || !opt_gt ? &lockalloc : &globalloc), v)) goto error; } for (; i < vec_size(self->locals); ++i) @@ -2297,6 +2256,9 @@ bool ir_function_allocate_locals(ir_function *self) if (vec_size(v->writes) == 1 && v->writes[0]->opcode == INSTR_CALL0) { v->store = store_return; + if (v->members[0]) v->members[0]->store = store_return; + if (v->members[1]) v->members[1]->store = store_return; + if (v->members[2]) v->members[2]->store = store_return; ++opts_optimizationcount[OPTIM_CALL_STORES]; continue; } @@ -2431,9 +2393,10 @@ static bool ir_block_living_lock(ir_block *self) bool changed = false; for (i = 0; i != vec_size(self->living); ++i) { - if (!self->living[i]->locked) + if (!self->living[i]->locked) { + self->living[i]->locked = true; changed = true; - self->living[i]->locked = true; + } } return changed; } @@ -2481,7 +2444,9 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change size_t i, o, p, mem; /* bitmasks which operands are read from or written to */ size_t read, write; - char dbg_ind[16] = { '#', '0' }; + char dbg_ind[16]; + dbg_ind[0] = '#'; + dbg_ind[1] = '0'; (void)dbg_ind; if (prev) @@ -2498,19 +2463,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change /* See which operands are read and write operands */ ir_op_read_write(instr->opcode, &read, &write); - if (instr->opcode == INSTR_MUL_VF) - { - /* the float source will get an additional lifetime */ - tempbool = ir_value_life_merge(instr->_ops[2], instr->eid+1); - *changed = *changed || tempbool; - } - else if (instr->opcode == INSTR_MUL_FV) - { - /* the float source will get an additional lifetime */ - tempbool = ir_value_life_merge(instr->_ops[1], instr->eid+1); - *changed = *changed || tempbool; - } - /* Go through the 3 main operands * writes first, then reads */ @@ -2584,6 +2536,25 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change } } + if (instr->opcode == INSTR_MUL_VF) + { + value = instr->_ops[2]; + /* the float source will get an additional lifetime */ + if (ir_value_life_merge(value, instr->eid+1)) + *changed = true; + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + *changed = true; + } + else if (instr->opcode == INSTR_MUL_FV) + { + value = instr->_ops[1]; + /* the float source will get an additional lifetime */ + if (ir_value_life_merge(value, instr->eid+1)) + *changed = true; + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + *changed = true; + } + for (o = 0; o < 3; ++o) { if (!instr->_ops[o]) /* no such operand */ @@ -2652,8 +2623,10 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change tempbool = ir_block_living_add_instr(self, instr->eid); /*con_err( "living added values\n");*/ *changed = *changed || tempbool; - } + /* the "entry" instruction ID */ + tempbool = ir_block_living_add_instr(self, instr->eid-1); + *changed = *changed || tempbool; if (self->run_id == self->owner->run_id) return true; @@ -2767,7 +2740,6 @@ static bool gen_blocks_recursive(ir_function *func, ir_block *block) size_t stidx; size_t i; -tailcall: block->generated = true; block->code_start = vec_size(code_statements); for (i = 0; i < vec_size(block->instr); ++i) @@ -2784,10 +2756,8 @@ tailcall: /* for uncoditional jumps, if the target hasn't been generated * yet, we generate them right here. */ - if (!target->generated) { - block = target; - goto tailcall; - } + if (!target->generated) + return gen_blocks_recursive(func, target); /* otherwise we generate a jump instruction */ stmt.opcode = INSTR_GOTO; @@ -2825,16 +2795,12 @@ tailcall: code_push_statement(&stmt, instr->context.line); } if (!ontrue->generated) { - if (onfalse->generated) { - block = ontrue; - goto tailcall; - } + if (onfalse->generated) + return gen_blocks_recursive(func, ontrue); } if (!onfalse->generated) { - if (ontrue->generated) { - block = onfalse; - goto tailcall; - } + if (ontrue->generated) + return gen_blocks_recursive(func, onfalse); } /* neither ontrue nor onfalse exist */ stmt.opcode = INSTR_IFNOT; @@ -2856,7 +2822,7 @@ tailcall: if (onfalse->generated) { /* fixup the jump address */ code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx); - if (code_statements[stidx].o2.s1 == 1) { + if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) { code_statements[stidx] = code_statements[stidx+1]; if (code_statements[stidx].o1.s1 < 0) code_statements[stidx].o1.s1++; @@ -2881,15 +2847,14 @@ tailcall: code_push_statement(&stmt, instr->context.line); return true; } - else if (code_statements[stidx].o2.s1 == 1) { + else if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) { code_statements[stidx] = code_statements[stidx+1]; if (code_statements[stidx].o1.s1 < 0) code_statements[stidx].o1.s1++; code_pop_statement(); } /* if not, generate now */ - block = onfalse; - goto tailcall; + return gen_blocks_recursive(func, onfalse); } if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) @@ -2912,6 +2877,8 @@ tailcall: if (param->vtype == TYPE_FIELD) stmt.opcode = field_store_instr[param->fieldtype]; + else if (param->vtype == TYPE_NIL) + stmt.opcode = INSTR_STORE_V; else stmt.opcode = type_store_instr[param->vtype]; stmt.o1.u1 = ir_value_code_addr(param); @@ -2939,6 +2906,8 @@ tailcall: if (param->vtype == TYPE_FIELD) stmt.opcode = field_store_instr[param->fieldtype]; + else if (param->vtype == TYPE_NIL) + stmt.opcode = INSTR_STORE_V; else stmt.opcode = type_store_instr[param->vtype]; stmt.o1.u1 = ir_value_code_addr(param); @@ -3619,6 +3588,12 @@ bool ir_builder_generate(ir_builder *self, const char *filename) } } + /* generate nil */ + ir_value_code_setaddr(self->nil, vec_size(code_globals)); + vec_push(code_globals, 0); + vec_push(code_globals, 0); + vec_push(code_globals, 0); + /* generate global temps */ self->first_common_globaltemp = vec_size(code_globals); for (i = 0; i < self->max_globaltemps; ++i) { @@ -3734,6 +3709,10 @@ void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...)) oprintf("endmodule %s\n", b->name); } +static const char *storenames[] = { + "[global]", "[local]", "[param]", "[value]", "[return]" +}; + void ir_function_dump(ir_function *f, char *ind, int (*oprintf)(const char*, ...)) { @@ -3764,7 +3743,12 @@ void ir_function_dump(ir_function *f, char *ind, attr = "unique "; else if (v->locked) attr = "locked "; - oprintf("%s\t%s: %s@%i ", ind, v->name, attr, (int)v->code.local); + oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype], + storenames[v->store], + attr, (v->callparam ? "callparam " : ""), + (int)v->code.local); + if (!v->life) + oprintf("[null]"); for (l = 0; l < vec_size(v->life); ++l) { oprintf("[%i,%i] ", v->life[l].start, v->life[l].end); } @@ -3773,13 +3757,7 @@ void ir_function_dump(ir_function *f, char *ind, ir_value *vm = v->members[m]; if (!vm) continue; - if (vm->unique_life && vm->locked) - attr = "unique,locked "; - else if (vm->unique_life) - attr = "unique "; - else if (vm->locked) - attr = "locked "; - oprintf("%s\t%s: %s@%i ", ind, vm->name, attr, (int)vm->code.local); + oprintf("%s\t%s: @%i ", ind, vm->name, (int)vm->code.local); for (l = 0; l < vec_size(vm->life); ++l) { oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end); } @@ -3787,13 +3765,41 @@ void ir_function_dump(ir_function *f, char *ind, } } for (i = 0; i < vec_size(f->values); ++i) { - size_t l; + const char *attr = ""; + size_t l, m; ir_value *v = f->values[i]; - oprintf("%s\t%s: @%i ", ind, v->name, (int)v->code.local); + if (v->unique_life && v->locked) + attr = "unique,locked "; + else if (v->unique_life) + attr = "unique "; + else if (v->locked) + attr = "locked "; + oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype], + storenames[v->store], + attr, (v->callparam ? "callparam " : ""), + (int)v->code.local); + if (!v->life) + oprintf("[null]"); for (l = 0; l < vec_size(v->life); ++l) { oprintf("[%i,%i] ", v->life[l].start, v->life[l].end); } oprintf("\n"); + for (m = 0; m < 3; ++m) { + ir_value *vm = v->members[m]; + if (!vm) + continue; + if (vm->unique_life && vm->locked) + attr = "unique,locked "; + else if (vm->unique_life) + attr = "unique "; + else if (vm->locked) + attr = "locked "; + oprintf("%s\t%s: %s@%i ", ind, vm->name, attr, (int)vm->code.local); + for (l = 0; l < vec_size(vm->life); ++l) { + oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end); + } + oprintf("\n"); + } } if (vec_size(f->blocks)) { @@ -3817,6 +3823,8 @@ void ir_block_dump(ir_block* b, char *ind, oprintf("%s:%s\n", ind, b->label); strncat(ind, "\t", IND_BUFSZ); + if (b->instr && b->instr[0]) + oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1)); for (i = 0; i < vec_size(b->instr); ++i) ir_instr_dump(b->instr[i], ind, oprintf); ind[strlen(ind)-1] = 0;