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;
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 &&
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*);
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
# 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
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;
}
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);
}
}
}
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))
{
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 */
{
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]);
}