Merge branch 'master' of github.com:graphitemaster/gmqcc

This commit is contained in:
Dale Weiler 2012-12-29 14:42:17 +00:00
commit d700bb66b2
7 changed files with 109 additions and 6 deletions

10
ast.c
View file

@ -570,7 +570,8 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel
self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
}
self->owner = owner;
self->rvalue = false;
self->owner = owner;
ast_propagate_effects(self, owner);
self->field = field;
@ -2082,14 +2083,17 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va
ir_value *vec;
/* in QC this is always an lvalue */
(void)lvalue;
if (lvalue && self->rvalue) {
compile_error(ast_ctx(self), "not an l-value (member access)");
return false;
}
if (self->expression.outl) {
*out = self->expression.outl;
return true;
}
cgen = self->owner->expression.codegen;
if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec))
return false;
if (vec->vtype != TYPE_VECTOR &&

1
ast.h
View file

@ -324,6 +324,7 @@ struct ast_member_s
ast_expression *owner;
unsigned int field;
const char *name;
bool rvalue;
};
ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int field, const char *name);
void ast_member_delete(ast_member*);

View file

@ -490,6 +490,15 @@ instruction is added for several reasons. (For example the qcvm's
disassemble switch uses it to know when the function ends.). This
optimization replaces that last RETURN with DONE rather than adding
the DONE additionally.
.TP
.B -Ovector-components
Because traditional QC code doesn't allow you to access individual
vector components of a computed vector without storing it in a local
first, sometimes people multiply it by a constant like '0 1 0' to get,
in this case, the y component of a vector. This optimization will turn
such a multiplication into a direct component access. If the factor is
anything other than 1, a float-multiplication will be added, which is
still faster than a vector multiplication.
.SH CONFIG
The configuration file is similar to regular .ini files. Comments
start with hashtags or semicolons, sections are written in square

View file

@ -232,3 +232,7 @@
# Do not create a RETURN instruction at the end functions of return-type void.
VOID_RETURN = true
# Turn extraction-multiplications such as (a_vector * '0 1 0')
# into direct component accesses
VECTOR_COMPONENTS = true

32
ir.c
View file

@ -2310,6 +2310,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;
}
@ -3779,7 +3782,7 @@ 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@%i ", ind, v->name, type_name[v->vtype], attr, (int)v->code.local);
for (l = 0; l < vec_size(v->life); ++l) {
oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
}
@ -3802,13 +3805,36 @@ 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@%i ", ind, v->name, type_name[v->vtype], attr, (int)v->code.local);
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))
{

View file

@ -95,6 +95,7 @@
GMQCC_DEFINE_FLAG(OVERLAP_STRINGS, 2)
GMQCC_DEFINE_FLAG(CALL_STORES, 1)
GMQCC_DEFINE_FLAG(VOID_RETURN, 1)
GMQCC_DEFINE_FLAG(VECTOR_COMPONENTS, 1)
#endif
/* some cleanup so we don't have to */

View file

@ -800,6 +800,64 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
{
if (CanConstFold(exprs[0], exprs[1]))
out = (ast_expression*)parser_const_float(parser, vec3_mulvv(ConstV(0), ConstV(1)));
else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[0])) {
vector vec = ConstV(0);
if (!vec.y && !vec.z) { /* 'n 0 0' * v */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.x != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out);
}
else if (!vec.x && !vec.z) { /* '0 n 0' * v */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.y != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out);
}
else if (!vec.x && !vec.y) { /* '0 n 0' * v */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.z != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out);
}
else
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
}
else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[1])) {
vector vec = ConstV(1);
if (!vec.y && !vec.z) { /* v * 'n 0 0' */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.x != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x));
}
else if (!vec.x && !vec.z) { /* v * '0 n 0' */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.y != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y));
}
else if (!vec.x && !vec.y) { /* v * '0 n 0' */
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL);
out->expression.node.keep = false;
((ast_member*)out)->rvalue = true;
if (vec.z != 1)
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z));
}
else
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
}
else
out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
}