var = new(ctx) ir_variable(sig->return_type,
talloc_asprintf(ctx, "%s_retval",
- sig->function_name()));
+ sig->function_name()),
+ ir_var_temporary);
instructions->push_tail(var);
deref = new(ctx) ir_dereference_variable(var);
assert(!parameters->is_empty());
ir_variable *var = new(ctx) ir_variable(type,
- talloc_strdup(ctx, "vec_ctor"));
+ talloc_strdup(ctx, "vec_ctor"),
+ ir_var_temporary);
instructions->push_tail(var);
/* There are two kinds of vector constructors.
assert(!parameters->is_empty());
ir_variable *var = new(ctx) ir_variable(type,
- talloc_strdup(ctx, "mat_ctor"));
+ talloc_strdup(ctx, "mat_ctor"),
+ ir_var_temporary);
instructions->push_tail(var);
/* There are three kinds of matrix constructors.
*/
ir_variable *rhs_var =
new(ctx) ir_variable(glsl_type::vec4_type,
- talloc_strdup(ctx, "mat_ctor_vec"));
+ talloc_strdup(ctx, "mat_ctor_vec"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_constant_data zero;
*/
ir_variable *const rhs_var =
new(ctx) ir_variable(first_param->type,
- talloc_strdup(ctx, "mat_ctor_mat"));
+ talloc_strdup(ctx, "mat_ctor_mat"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_dereference *const rhs_var_ref =
*/
ir_variable *rhs_var =
new(ctx) ir_variable(rhs->type,
- talloc_strdup(ctx, "mat_ctor_vec"));
+ talloc_strdup(ctx, "mat_ctor_vec"),
+ ir_var_temporary);
instructions->push_tail(rhs_var);
ir_dereference *rhs_var_ref =
continue;
/* Create a temporary containing the matrix. */
- ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp");
+ ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
+ ir_var_temporary);
instructions->push_tail(var);
instructions->push_tail(new(ctx) ir_assignment(new(ctx)
ir_dereference_variable(var), matrix, NULL));
* temporary and return a deref of that temporary. If the rvalue
* ends up not being used, the temp will get copy-propagated out.
*/
- ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp");
+ ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
+ ir_var_temporary);
ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
instructions->push_tail(var);
instructions->push_tail(new(ctx) ir_assignment(deref_var,
ir_variable *var;
/* FINISHME: Give unique names to the temporaries. */
- var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp");
+ var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp",
+ ir_var_temporary);
instructions->push_tail(var);
var->mode = ir_var_auto;
type = glsl_type::bool_type;
} else {
ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
- "and_tmp");
+ "and_tmp",
+ ir_var_temporary);
instructions->push_tail(tmp);
ir_if *const stmt = new(ctx) ir_if(op[0]);
type = glsl_type::bool_type;
} else {
ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
- "or_tmp");
+ "or_tmp",
+ ir_var_temporary);
instructions->push_tail(tmp);
ir_if *const stmt = new(ctx) ir_if(op[0]);
&& (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) {
result = (cond_val->value.b[0]) ? then_val : else_val;
} else {
- ir_variable *const tmp = new(ctx) ir_variable(type, "conditional_tmp");
+ ir_variable *const tmp =
+ new(ctx) ir_variable(type, "conditional_tmp", ir_var_temporary);
instructions->push_tail(tmp);
ir_if *const stmt = new(ctx) ir_if(op[0]);
}
}
+ /* If there is no qualifier that changes the mode of the variable, leave
+ * the setting alone.
+ */
if (qual->in && qual->out)
var->mode = ir_var_inout;
else if (qual->attribute || qual->in
var->mode = ir_var_out;
else if (qual->uniform)
var->mode = ir_var_uniform;
- else
- var->mode = ir_var_auto;
if (qual->uniform)
var->shader_in = true;
var_type = decl_type;
}
- var = new(ctx) ir_variable(var_type, decl->identifier);
+ var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
/* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification;
*
}
is_void = false;
- ir_variable *var = new(ctx) ir_variable(type, this->identifier);
+ ir_variable *var = new(ctx) ir_variable(type, this->identifier, ir_var_in);
/* FINISHME: Handle array declarations. Note that this requires
* FINISHME: complete handling of constant expressions.
* for function parameters the default mode is 'in'.
*/
apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
- if (var->mode == ir_var_auto)
- var->mode = ir_var_in;
instructions->push_tail(var);
snprintf(param_name, 10, "p%08X", i);
ir_variable *var = (this->base_type == GLSL_TYPE_ARRAY)
- ? new(ctx) ir_variable(fields.array, param_name)
- : new(ctx) ir_variable(fields.structure[i].type, param_name);
+ ? new(ctx) ir_variable(fields.array, param_name, ir_var_in)
+ : new(ctx) ir_variable(fields.structure[i].type, param_name, ir_var_in);
- var->mode = ir_var_in;
declarations[i] = var;
sig->parameters.push_tail(var);
}
* the same type as the constructor. After initializing __retval,
* __retval is returned.
*/
- ir_variable *retval = new(ctx) ir_variable(this, "__retval");
+ ir_variable *retval = new(ctx) ir_variable(this, "__retval", ir_var_auto);
sig->body.push_tail(retval);
for (unsigned i = 0; i < length; i++) {
return this->val->variable_referenced();
}
-ir_variable::ir_variable(const struct glsl_type *type, const char *name)
+
+ir_variable::ir_variable(const struct glsl_type *type, const char *name,
+ ir_variable_mode mode)
: max_array_access(0), read_only(false), centroid(false), invariant(false),
shader_in(false), shader_out(false),
- mode(ir_var_auto), interpolation(ir_var_smooth), array_lvalue(false)
+ mode(mode), interpolation(ir_var_smooth), array_lvalue(false)
{
this->ir_type = ir_type_variable;
this->type = type;
ir_var_uniform,
ir_var_in,
ir_var_out,
- ir_var_inout
+ ir_var_inout,
+ ir_var_temporary /**< Temporary variable generated during compilation. */
};
enum ir_variable_interpolation {
class ir_variable : public ir_instruction {
public:
- ir_variable(const struct glsl_type *, const char *);
+ ir_variable(const struct glsl_type *, const char *, ir_variable_mode);
virtual ir_variable *clone(struct hash_table *ht) const;
ir_variable::clone(struct hash_table *ht) const
{
void *ctx = talloc_parent(this);
- ir_variable *var = new(ctx) ir_variable(type, name);
+ ir_variable *var = new(ctx) ir_variable(this->type, this->name,
+ (ir_variable_mode) this->mode);
var->max_array_access = this->max_array_access;
var->read_only = this->read_only;
var->invariant = this->invariant;
var->shader_in = this->shader_in;
var->shader_out = this->shader_out;
- var->mode = this->mode;
var->interpolation = this->interpolation;
var->array_lvalue = this->array_lvalue;
var->location = this->location;
if (!this->predicate(ir))
return ir;
- var = new(ctx) ir_variable(ir->type, "flattening_tmp");
+ var = new(ctx) ir_variable(ir->type, "flattening_tmp", ir_var_temporary);
base_ir->insert_before(var);
assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
switch ((enum ir_variable_mode)(param->mode)) {
case ir_var_auto:
case ir_var_uniform:
+ case ir_var_temporary:
/* These are all error conditions. It is invalid for a parameter to
* a function to be declared as auto (not in, out, or inout) or
* as uniform.
/* Generate storage for the return value. */
if (this->callee->return_type) {
- retval = new(ctx) ir_variable(this->callee->return_type, "__retval");
+ retval = new(ctx) ir_variable(this->callee->return_type, "__retval",
+ ir_var_auto);
next_ir->insert_before(retval);
}
} else {
ir_assignment *assign;
ir_variable *new_var = new(ir) ir_variable(then_return->value->type,
- "if_return_tmp");
+ "if_return_tmp",
+ ir_var_temporary);
ir->insert_before(new_var);
assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(new_var),
* simpler.
*/
cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
- "if_to_cond_assign_condition");
+ "if_to_cond_assign_condition",
+ ir_var_temporary);
ir->insert_before(cond_var);
deref = new(mem_ctx) ir_dereference_variable(cond_var);
ir_assignment *assign;
op_var[i] = new(base_ir) ir_variable(expr->operands[i]->type,
- "mat_op_to_vec");
+ "mat_op_to_vec",
+ ir_var_temporary);
base_ir->insert_before(op_var[i]);
lhs_deref = new(base_ir) ir_dereference_variable(op_var[i]);
if (ir->operation != ir_binop_mod)
return visit_continue;
- ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b");
+ ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b",
+ ir_var_temporary);
this->base_ir->insert_before(temp);
ir_assignment *assign;
return NULL;
}
- ir_variable *var = new(ctx) ir_variable(type, var_name->value());
+ ir_variable *var = new(ctx) ir_variable(type, var_name->value(),
+ ir_var_auto);
foreach_iter(exec_list_iterator, it, quals->subexpressions) {
s_symbol *qualifier = SX_AS_SYMBOL(it.get());
const glsl_type *type, exec_list *instructions,
glsl_symbol_table *symtab)
{
- ir_variable *var = new(symtab) ir_variable(type, name);
+ ir_variable *var = new(symtab) ir_variable(type, name, mode);
- var->mode = mode;
switch (var->mode) {
case ir_var_auto:
var->read_only = true;
/* Store the index to a temporary to avoid reusing its tree. */
index = new(base_ir) ir_variable(glsl_type::int_type,
- "vec_index_tmp_i");
+ "vec_index_tmp_i",
+ ir_var_temporary);
base_ir->insert_before(index);
deref = new(base_ir) ir_dereference_variable(index);
assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
base_ir->insert_before(assign);
/* Temporary where we store whichever value we swizzle out. */
- var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v");
+ var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
+ ir_var_temporary);
base_ir->insert_before(var);
/* Generate a conditional move of each vector element to the temp. */
assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
/* Store the index to a temporary to avoid reusing its tree. */
- index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i");
+ index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
+ ir_var_temporary);
ir->insert_before(index);
deref = new(ir) ir_dereference_variable(index);
assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
ir->insert_before(assign);
/* Store the RHS to a temporary to avoid reusing its tree. */
- var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v");
+ var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
+ ir_var_temporary);
ir->insert_before(var);
deref = new(ir) ir_dereference_variable(var);
assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
case ir_var_in: return "shader input";
case ir_var_out: return "shader output";
case ir_var_inout: return "shader inout";
+
+ case ir_var_temporary:
default:
assert(!"Should not get here.");
return "invalid variable";
if (uniforms_only && (var->mode != ir_var_uniform))
continue;
+ /* Don't cross validate temporaries that are at global scope. These
+ * will eventually get pulled into the shaders 'main'.
+ */
+ if (var->mode == ir_var_temporary)
+ continue;
+
/* If a global with this name has already been seen, verify that the
* new instance has the same type. In addition, if the globals have
* initializers, the values of the initializers must be the same.
*/
void
remap_variables(ir_instruction *inst, glsl_symbol_table *symbols,
- exec_list *instructions)
+ exec_list *instructions, hash_table *temps)
{
class remap_visitor : public ir_hierarchical_visitor {
public:
- remap_visitor(glsl_symbol_table *symbols, exec_list *instructions)
+ remap_visitor(glsl_symbol_table *symbols, exec_list *instructions,
+ hash_table *temps)
{
this->symbols = symbols;
this->instructions = instructions;
+ this->temps = temps;
}
virtual ir_visitor_status visit(ir_dereference_variable *ir)
{
+ if (ir->var->mode == ir_var_temporary) {
+ ir_variable *var = (ir_variable *) hash_table_find(temps, ir->var);
+
+ assert(var != NULL);
+ ir->var = var;
+ return visit_continue;
+ }
+
ir_variable *const existing =
this->symbols->get_variable(ir->var->name);
if (existing != NULL)
this->symbols->add_variable(copy->name, copy);
this->instructions->push_head(copy);
+ ir->var = copy;
}
return visit_continue;
private:
glsl_symbol_table *symbols;
exec_list *instructions;
+ hash_table *temps;
};
- remap_visitor v(symbols, instructions);
+ remap_visitor v(symbols, instructions, temps);
inst->accept(&v);
}
move_non_declarations(exec_list *instructions, exec_node *last,
bool make_copies, gl_shader *target)
{
+ hash_table *temps = NULL;
+
+ if (make_copies)
+ temps = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
+
foreach_list_safe(node, instructions) {
ir_instruction *inst = (ir_instruction *) node;
- if (inst->as_variable() || inst->as_function())
+ if (inst->as_function())
+ continue;
+
+ ir_variable *var = inst->as_variable();
+ if ((var != NULL) && (var->mode != ir_var_temporary))
continue;
- assert(inst->as_assignment());
+ assert(inst->as_assignment()
+ || ((var != NULL) && (var->mode == ir_var_temporary)));
if (make_copies) {
inst = inst->clone(NULL);
- remap_variables(inst, target->symbols, target->ir);
+
+ if (var != NULL)
+ hash_table_insert(temps, inst, var);
+ else
+ remap_variables(inst, target->symbols, target->ir, temps);
} else {
inst->remove();
}
last = inst;
}
+ if (make_copies)
+ hash_table_dtor(temps);
+
return last;
}
break;
case ir_var_auto:
+ case ir_var_temporary:
entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY,
this->next_temp);
this->variables.push_tail(entry);