#include "glsl_types.h"
#include "program/hash_table.h"
#include "ir.h"
+#include "ir_builder.h"
+
+using namespace ir_builder;
static void
detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
}
}
-ir_rvalue *
+static bool
do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
const char *non_lvalue_description,
- ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
+ ir_rvalue *lhs, ir_rvalue *rhs,
+ ir_rvalue **out_rvalue, bool needs_rvalue,
+ bool is_initializer,
YYLTYPE lhs_loc)
{
void *ctx = state;
* to handle things like:
*
* i = j += 1;
- *
- * So we always just store the computed value being assigned to a
- * 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_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, rhs));
- deref_var = new(ctx) ir_dereference_variable(var);
+ if (needs_rvalue) {
+ ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
+ ir_var_temporary);
+ instructions->push_tail(var);
+ instructions->push_tail(assign(var, rhs));
+
+ if (!error_emitted) {
+ ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
+ instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
+ }
+ ir_rvalue *rvalue = new(ctx) ir_dereference_variable(var);
- if (!error_emitted)
- instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
+ if (extract_channel) {
+ rvalue = new(ctx) ir_expression(ir_binop_vector_extract,
+ rvalue,
+ extract_channel->clone(ctx, NULL));
+ }
- if (extract_channel) {
- return new(ctx) ir_expression(ir_binop_vector_extract,
- new(ctx) ir_dereference_variable(var),
- extract_channel->clone(ctx, NULL));
+ *out_rvalue = rvalue;
+ } else {
+ if (!error_emitted)
+ instructions->push_tail(new(ctx) ir_assignment(lhs, rhs));
+ *out_rvalue = NULL;
}
- return new(ctx) ir_dereference_variable(var);
+
+ return error_emitted;
}
static ir_rvalue *
return NULL;
}
+void
+ast_function_expression::hir_no_rvalue(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ (void)hir(instructions, state);
+}
+
+void
+ast_aggregate_initializer::hir_no_rvalue(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ (void)hir(instructions, state);
+}
+
static ir_rvalue *
do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
{
ir_rvalue *
ast_expression::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
+{
+ return do_hir(instructions, state, true);
+}
+
+void
+ast_expression::hir_no_rvalue(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ do_hir(instructions, state, false);
+}
+
+ir_rvalue *
+ast_expression::do_hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ bool needs_rvalue)
{
void *ctx = state;
static const int operations[AST_NUM_OPERATORS] = {
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0], op[1], false,
- this->subexpressions[0]->get_location());
- error_emitted = result->type->is_error();
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0], op[1], &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
break;
}
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
- error_emitted = (op[0]->type->is_error());
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
/* GLSL 1.10 does not allow array assignment. However, we don't have to
* explicitly test for this because none of the binary expression
temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
- error_emitted = type->is_error();
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
break;
}
&loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
break;
}
state, &loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
break;
}
temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error();
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &result, needs_rvalue, false,
+ this->subexpressions[0]->get_location());
break;
}
*/
result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
- (void)do_assignment(instructions, state,
- this->subexpressions[0]->non_lvalue_description,
- op[0]->clone(ctx, NULL), temp_rhs, false,
- this->subexpressions[0]->get_location());
+ ir_rvalue *junk_rvalue;
+ error_emitted =
+ do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs,
+ &junk_rvalue, false, false,
+ this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error();
break;
}
}
}
type = NULL; /* use result->type, not type. */
- assert(result != NULL);
+ assert(result != NULL || !needs_rvalue);
- if (result->type->is_error() && !error_emitted)
+ if (result && result->type->is_error() && !error_emitted)
_mesa_glsl_error(& loc, state, "type mismatch");
return result;
* anything in that case.
*/
if (expression != NULL)
- expression->hir(instructions, state);
+ expression->hir_no_rvalue(instructions, state);
/* Statements do not have r-values.
*/
*/
const glsl_type *initializer_type;
if (!type->qualifier.flags.q.uniform) {
- result = do_assignment(initializer_instructions, state,
- NULL,
- lhs, rhs, true,
- type->get_location());
+ do_assignment(initializer_instructions, state,
+ NULL,
+ lhs, rhs,
+ &result, true,
+ true,
+ type->get_location());
initializer_type = result->type;
} else
initializer_type = rhs->type;