+static void ir_builder_collect_reusables(ir_builder *builder) {
+ size_t i;
+ ir_value **reusables = NULL;
+ for (i = 0; i < vec_size(builder->globals); ++i) {
+ ir_value *value = builder->globals[i];
+ if (value->vtype != TYPE_FLOAT || !value->hasvalue)
+ continue;
+ if (value->cvq == CV_CONST || (value->name && value->name[0] == '#')) {
+ vec_push(reusables, value);
+ }
+ }
+ builder->const_floats = reusables;
+}
+
+static void ir_builder_split_vector(ir_builder *self, ir_value *vec) {
+ size_t i, count;
+ ir_value* found[3] = { NULL, NULL, NULL };
+
+ /* must not be written to */
+ if (vec_size(vec->writes))
+ return;
+ /* must not be trying to access individual members */
+ if (vec->members[0] || vec->members[1] || vec->members[2])
+ return;
+ /* should be actually used otherwise it won't be generated anyway */
+ count = vec_size(vec->reads);
+ if (!count)
+ return;
+
+ /* may only be used directly as function parameters, so if we find some other instruction cancel */
+ for (i = 0; i != count; ++i) {
+ /* we only split vectors if they're used directly as parameter to a call only! */
+ ir_instr *user = vec->reads[i];
+ if ((user->opcode < INSTR_CALL0 || user->opcode > INSTR_CALL8) && user->opcode != VINSTR_NRCALL)
+ return;
+ }
+
+ vec->flags |= IR_FLAG_SPLIT_VECTOR;
+
+ /* find existing floats making up the split */
+ count = vec_size(self->const_floats);
+ for (i = 0; i != count; ++i) {
+ ir_value *c = self->const_floats[i];
+ if (!found[0] && c->constval.vfloat == vec->constval.vvec.x)
+ found[0] = c;
+ if (!found[1] && c->constval.vfloat == vec->constval.vvec.y)
+ found[1] = c;
+ if (!found[2] && c->constval.vfloat == vec->constval.vvec.z)
+ found[2] = c;
+ if (found[0] && found[1] && found[2])
+ break;
+ }
+
+ /* generate floats for not yet found components */
+ if (!found[0])
+ found[0] = ir_builder_imm_float(self, vec->constval.vvec.x, true);
+ if (!found[1]) {
+ if (vec->constval.vvec.y == vec->constval.vvec.x)
+ found[1] = found[0];
+ else
+ found[1] = ir_builder_imm_float(self, vec->constval.vvec.y, true);
+ }
+ if (!found[2]) {
+ if (vec->constval.vvec.z == vec->constval.vvec.x)
+ found[2] = found[0];
+ else if (vec->constval.vvec.z == vec->constval.vvec.y)
+ found[2] = found[1];
+ else
+ found[2] = ir_builder_imm_float(self, vec->constval.vvec.z, true);
+ }
+
+ /* the .members array should be safe to use here. */
+ vec->members[0] = found[0];
+ vec->members[1] = found[1];
+ vec->members[2] = found[2];
+
+ /* register the readers for these floats */
+ count = vec_size(vec->reads);
+ for (i = 0; i != count; ++i) {
+ vec_push(found[0]->reads, vec->reads[i]);
+ vec_push(found[1]->reads, vec->reads[i]);
+ vec_push(found[2]->reads, vec->reads[i]);
+ }
+}
+
+static void ir_builder_split_vectors(ir_builder *self) {
+ size_t i, count = vec_size(self->globals);
+ for (i = 0; i != count; ++i) {
+ ir_value *v = self->globals[i];
+ if (v->vtype != TYPE_VECTOR || !v->name || v->name[0] != '#')
+ continue;
+ ir_builder_split_vector(self, self->globals[i]);
+ }
+}
+