summaryrefslogtreecommitdiff
path: root/src/glsl/ir_reader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/ir_reader.cpp')
-rw-r--r--src/glsl/ir_reader.cpp76
1 files changed, 67 insertions, 9 deletions
diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp
index e57e03c307..a9cbf8ea94 100644
--- a/src/glsl/ir_reader.cpp
+++ b/src/glsl/ir_reader.cpp
@@ -32,6 +32,8 @@ extern "C" {
#include "glsl_types.h"
#include "s_expression.h"
+const static bool debug = false;
+
static void ir_read_error(_mesa_glsl_parse_state *, s_expression *,
const char *fmt, ...);
static const glsl_type *read_type(_mesa_glsl_parse_state *, s_expression *);
@@ -84,6 +86,9 @@ _mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions,
read_instructions(state, instructions, expr, NULL);
talloc_free(expr);
+
+ if (debug)
+ validate_ir_tree(instructions);
}
static void
@@ -94,6 +99,10 @@ ir_read_error(_mesa_glsl_parse_state *state, s_expression *expr,
state->error = true;
+ if (state->current_function != NULL)
+ state->info_log = talloc_asprintf_append(state->info_log,
+ "In function %s:\n",
+ state->current_function->function_name());
state->info_log = talloc_strdup_append(state->info_log, "error: ");
va_start(ap, fmt);
@@ -209,7 +218,6 @@ read_function(_mesa_glsl_parse_state *st, s_list *list, bool skip_body)
ir_function *f = st->symbols->get_function(name->value());
if (f == NULL) {
f = new(ctx) ir_function(name->value());
- f->is_builtin = true;
added = st->symbols->add_function(f->name, f);
assert(added);
}
@@ -282,6 +290,7 @@ read_function_sig(_mesa_glsl_parse_state *st, ir_function *f, s_list *list,
if (sig == NULL && skip_body) {
/* If scanning for prototypes, generate a new signature. */
sig = new(ctx) ir_function_signature(return_type);
+ sig->is_builtin = true;
f->add_signature(sig);
} else if (sig != NULL) {
const char *badvar = sig->qualifiers_match(&hir_parameters);
@@ -310,7 +319,9 @@ read_function_sig(_mesa_glsl_parse_state *st, ir_function *f, s_list *list,
ir_read_error(st, list, "function %s redefined", f->name);
return;
}
+ st->current_function = sig;
read_instructions(st, &sig->body, body_list, NULL);
+ st->current_function = NULL;
sig->is_defined = true;
}
@@ -331,8 +342,17 @@ read_instructions(_mesa_glsl_parse_state *st, exec_list *instructions,
foreach_iter(exec_list_iterator, it, list->subexpressions) {
s_expression *sub = (s_expression*) it.get();
ir_instruction *ir = read_instruction(st, sub, loop_ctx);
- if (ir != NULL)
- instructions->push_tail(ir);
+ if (ir != NULL) {
+ /* Global variable declarations should be moved to the top, before
+ * any functions that might use them. Functions are added to the
+ * instruction stream when scanning for prototypes, so without this
+ * hack, they always appear before variable declarations.
+ */
+ if (st->current_function == NULL && ir->as_variable() != NULL)
+ instructions->push_head(ir);
+ else
+ instructions->push_tail(ir);
+ }
}
}
@@ -575,23 +595,56 @@ static ir_assignment *
read_assignment(_mesa_glsl_parse_state *st, s_list *list)
{
void *ctx = st;
- if (list->length() != 4) {
- ir_read_error(st, list, "expected (assign <condition> <lhs> <rhs>)");
+ if (list->length() != 5) {
+ ir_read_error(st, list, "expected (assign <condition> (<write mask>) "
+ "<lhs> <rhs>)");
return NULL;
}
s_expression *cond_expr = (s_expression*) list->subexpressions.head->next;
- s_expression *lhs_expr = (s_expression*) cond_expr->next;
+ s_list *mask_list = SX_AS_LIST(cond_expr->next);
+ s_expression *lhs_expr = (s_expression*) cond_expr->next->next;
s_expression *rhs_expr = (s_expression*) lhs_expr->next;
- // FINISHME: Deal with "true" condition
ir_rvalue *condition = read_rvalue(st, cond_expr);
if (condition == NULL) {
ir_read_error(st, NULL, "when reading condition of assignment");
return NULL;
}
- ir_rvalue *lhs = read_rvalue(st, lhs_expr);
+ if (mask_list == NULL || mask_list->length() > 1) {
+ ir_read_error(st, mask_list, "expected () or (<write mask>)");
+ return NULL;
+ }
+
+ unsigned mask = 0;
+ if (mask_list->length() == 1) {
+ s_symbol *mask_symbol = SX_AS_SYMBOL(mask_list->subexpressions.head);
+ if (mask_symbol == NULL) {
+ ir_read_error(st, list, "expected a write mask; found non-symbol");
+ return NULL;
+ }
+
+ const char *mask_str = mask_symbol->value();
+ unsigned mask_length = strlen(mask_str);
+ if (mask_length > 4) {
+ ir_read_error(st, list, "invalid write mask: %s", mask_str);
+ return NULL;
+ }
+
+ const unsigned idx_map[] = { 3, 0, 1, 2 }; /* w=bit 3, x=0, y=1, z=2 */
+
+ for (unsigned i = 0; i < mask_length; i++) {
+ if (mask_str[i] < 'w' || mask_str[i] > 'z') {
+ ir_read_error(st, list, "write mask contains invalid character: %c",
+ mask_str[i]);
+ return NULL;
+ }
+ mask |= 1 << idx_map[mask_str[i] - 'w'];
+ }
+ }
+
+ ir_dereference *lhs = read_dereference(st, lhs_expr);
if (lhs == NULL) {
ir_read_error(st, NULL, "when reading left-hand side of assignment");
return NULL;
@@ -603,7 +656,12 @@ read_assignment(_mesa_glsl_parse_state *st, s_list *list)
return NULL;
}
- return new(ctx) ir_assignment(lhs, rhs, condition);
+ if (mask == 0 && (lhs->type->is_vector() || lhs->type->is_scalar())) {
+ ir_read_error(st, list, "non-zero write mask required.");
+ return NULL;
+ }
+
+ return new(ctx) ir_assignment(lhs, rhs, condition, mask);
}
static ir_call *