2010-04-07 14:38:03 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2010 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
2010-06-22 10:38:52 -07:00
|
|
|
|
2010-04-07 14:38:03 -07:00
|
|
|
#include "ir_reader.h"
|
|
|
|
|
#include "glsl_parser_extras.h"
|
2016-01-18 11:35:29 +02:00
|
|
|
#include "compiler/glsl_types.h"
|
2010-04-07 14:38:03 -07:00
|
|
|
#include "s_expression.h"
|
|
|
|
|
|
2015-08-18 17:41:30 -07:00
|
|
|
static const bool debug = false;
|
2010-09-05 00:58:34 -07:00
|
|
|
|
2013-09-20 11:03:44 -07:00
|
|
|
namespace {
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
class ir_reader {
|
|
|
|
|
public:
|
|
|
|
|
ir_reader(_mesa_glsl_parse_state *);
|
|
|
|
|
|
|
|
|
|
void read(exec_list *instructions, const char *src, bool scan_for_protos);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void *mem_ctx;
|
|
|
|
|
_mesa_glsl_parse_state *state;
|
|
|
|
|
|
|
|
|
|
void ir_read_error(s_expression *, const char *fmt, ...);
|
|
|
|
|
|
|
|
|
|
const glsl_type *read_type(s_expression *);
|
|
|
|
|
|
|
|
|
|
void scan_for_prototypes(exec_list *, s_expression *);
|
|
|
|
|
ir_function *read_function(s_expression *, bool skip_body);
|
|
|
|
|
void read_function_sig(ir_function *, s_expression *, bool skip_body);
|
|
|
|
|
|
|
|
|
|
void read_instructions(exec_list *, s_expression *, ir_loop *);
|
|
|
|
|
ir_instruction *read_instruction(s_expression *, ir_loop *);
|
|
|
|
|
ir_variable *read_declaration(s_expression *);
|
|
|
|
|
ir_if *read_if(s_expression *, ir_loop *);
|
|
|
|
|
ir_loop *read_loop(s_expression *);
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
ir_call *read_call(s_expression *);
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_return *read_return(s_expression *);
|
|
|
|
|
ir_rvalue *read_rvalue(s_expression *);
|
|
|
|
|
ir_assignment *read_assignment(s_expression *);
|
|
|
|
|
ir_expression *read_expression(s_expression *);
|
|
|
|
|
ir_swizzle *read_swizzle(s_expression *);
|
|
|
|
|
ir_constant *read_constant(s_expression *);
|
|
|
|
|
ir_texture *read_texture(s_expression *);
|
2013-02-15 09:26:35 -06:00
|
|
|
ir_emit_vertex *read_emit_vertex(s_expression *);
|
|
|
|
|
ir_end_primitive *read_end_primitive(s_expression *);
|
2014-09-07 19:24:15 +12:00
|
|
|
ir_barrier *read_barrier(s_expression *);
|
2011-01-01 01:17:59 -08:00
|
|
|
|
|
|
|
|
ir_dereference *read_dereference(s_expression *);
|
2011-09-22 14:29:53 -07:00
|
|
|
ir_dereference_variable *read_var_ref(s_expression *);
|
2011-01-01 01:17:59 -08:00
|
|
|
};
|
|
|
|
|
|
2013-09-20 11:03:44 -07:00
|
|
|
} /* anonymous namespace */
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state)
|
|
|
|
|
{
|
|
|
|
|
this->mem_ctx = state;
|
|
|
|
|
}
|
2010-04-07 17:24:44 -07:00
|
|
|
|
2010-04-07 14:38:03 -07:00
|
|
|
void
|
|
|
|
|
_mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions,
|
2010-08-11 16:53:52 -07:00
|
|
|
const char *src, bool scan_for_protos)
|
2010-04-07 14:38:03 -07:00
|
|
|
{
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_reader r(state);
|
|
|
|
|
r.read(instructions, src, scan_for_protos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos)
|
|
|
|
|
{
|
2011-09-22 13:05:03 -07:00
|
|
|
void *sx_mem_ctx = ralloc_context(NULL);
|
|
|
|
|
s_expression *expr = s_expression::read_expression(sx_mem_ctx, src);
|
2010-04-07 14:38:03 -07:00
|
|
|
if (expr == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "couldn't parse S-Expression.");
|
2010-04-07 14:38:03 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2015-11-24 12:40:53 +01:00
|
|
|
|
2010-08-11 16:53:52 -07:00
|
|
|
if (scan_for_protos) {
|
2011-01-01 01:17:59 -08:00
|
|
|
scan_for_prototypes(instructions, expr);
|
2010-08-11 16:53:52 -07:00
|
|
|
if (state->error)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-04-21 17:52:36 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
read_instructions(instructions, expr, NULL);
|
2011-09-22 13:05:03 -07:00
|
|
|
ralloc_free(sx_mem_ctx);
|
2010-09-04 01:09:43 -07:00
|
|
|
|
2010-09-05 00:58:34 -07:00
|
|
|
if (debug)
|
|
|
|
|
validate_ir_tree(instructions);
|
2010-04-07 14:38:03 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
void
|
|
|
|
|
ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2010-04-21 15:47:34 -07:00
|
|
|
state->error = true;
|
2010-04-07 17:24:44 -07:00
|
|
|
|
2010-09-04 01:05:51 -07:00
|
|
|
if (state->current_function != NULL)
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_asprintf_append(&state->info_log, "In function %s:\n",
|
|
|
|
|
state->current_function->function_name());
|
|
|
|
|
ralloc_strcat(&state->info_log, "error: ");
|
2010-04-07 17:24:44 -07:00
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_vasprintf_append(&state->info_log, fmt, ap);
|
2010-04-07 17:24:44 -07:00
|
|
|
va_end(ap);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_strcat(&state->info_log, "\n");
|
2010-04-07 17:24:44 -07:00
|
|
|
|
2010-04-21 23:23:23 -07:00
|
|
|
if (expr != NULL) {
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_strcat(&state->info_log, "...in this context:\n ");
|
2010-04-21 23:23:23 -07:00
|
|
|
expr->print();
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_strcat(&state->info_log, "\n\n");
|
2010-04-21 23:23:23 -07:00
|
|
|
}
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *
|
|
|
|
|
ir_reader::read_type(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_base_type;
|
|
|
|
|
s_int *s_size;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "array", s_base_type, s_size };
|
|
|
|
|
if (MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *base_type = read_type(s_base_type);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (base_type == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading base type of array type");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-04-10 01:06:44 -07:00
|
|
|
|
2023-12-14 22:21:26 -08:00
|
|
|
return glsl_array_type(base_type, s_size->value(), 0);
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
2015-11-24 12:40:53 +01:00
|
|
|
|
2010-04-07 17:24:44 -07:00
|
|
|
s_symbol *type_sym = SX_AS_SYMBOL(expr);
|
|
|
|
|
if (type_sym == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected <type>");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *type = state->symbols->get_type(type_sym->value());
|
2010-04-07 17:24:44 -07:00
|
|
|
if (type == NULL)
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "invalid type: %s", type_sym->value());
|
2010-04-07 17:24:44 -07:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-09 17:40:51 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
void
|
|
|
|
|
ir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr)
|
2010-04-21 17:52:36 -07:00
|
|
|
{
|
|
|
|
|
s_list *list = SX_AS_LIST(expr);
|
|
|
|
|
if (list == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
|
2010-04-21 17:52:36 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 22:11:04 -07:00
|
|
|
foreach_in_list(s_list, sub, &list->subexpressions) {
|
|
|
|
|
if (!sub->is_list())
|
2010-04-21 17:52:36 -07:00
|
|
|
continue; // not a (function ...); ignore it.
|
|
|
|
|
|
|
|
|
|
s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head());
|
|
|
|
|
if (tag == NULL || strcmp(tag->value(), "function") != 0)
|
|
|
|
|
continue; // not a (function ...); ignore it.
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_function *f = read_function(sub, true);
|
2010-04-21 18:14:06 -07:00
|
|
|
if (f == NULL)
|
2010-04-21 17:52:36 -07:00
|
|
|
return;
|
2010-04-21 18:14:06 -07:00
|
|
|
instructions->push_tail(f);
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_function *
|
|
|
|
|
ir_reader::read_function(s_expression *expr, bool skip_body)
|
2010-04-21 17:52:36 -07:00
|
|
|
{
|
2010-07-07 15:23:27 -07:00
|
|
|
bool added = false;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_symbol *name;
|
2010-04-21 17:52:36 -07:00
|
|
|
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_pattern pat[] = { "function", name };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!PARTIAL_MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "Expected (function <name> (signature ...) ...)");
|
2010-04-21 18:14:06 -07:00
|
|
|
return NULL;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_function *f = state->symbols->get_function(name->value());
|
2010-04-21 18:14:06 -07:00
|
|
|
if (f == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
f = new(mem_ctx) ir_function(name->value());
|
|
|
|
|
added = state->symbols->add_function(f);
|
2010-04-21 18:14:06 -07:00
|
|
|
assert(added);
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2014-01-10 17:08:33 -08:00
|
|
|
/* Skip over "function" tag and function name (which are guaranteed to be
|
|
|
|
|
* present by the above PARTIAL_MATCH call).
|
|
|
|
|
*/
|
2016-06-27 14:42:57 -07:00
|
|
|
exec_node *node = ((s_list *) expr)->subexpressions.get_head_raw()->next->next;
|
2014-01-10 17:08:33 -08:00
|
|
|
for (/* nothing */; !node->is_tail_sentinel(); node = node->next) {
|
|
|
|
|
s_expression *s_sig = (s_expression *) node;
|
2011-01-01 01:17:59 -08:00
|
|
|
read_function_sig(f, s_sig, skip_body);
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
2010-07-07 15:23:27 -07:00
|
|
|
return added ? f : NULL;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
glsl: Store a predicate for whether a built-in signature is available.
For the upcoming built-in function rewrite, we'll need to be able to
answer "Is this built-in function signature available?".
This is actually a somewhat complex question, since it depends on the
language version, GLSL vs. GLSL ES, enabled extensions, and the current
shader stage.
Storing such a set of constraints in a structure would be painful, so
instead we store a function pointer. When creating a signature, we
simply point to a predicate that inspects _mesa_glsl_parse_state and
answers whether the signature is available in the current shader.
Unfortunately, IR reader doesn't actually know when built-in functions
are available, so this patch makes it lie and say that they're always
present. This allows us to hook up the new functionality; it just won't
be useful until real data is populated. In the meantime, the existing
profile mechanism ensures built-ins are available in the right places.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-08-30 16:00:43 -07:00
|
|
|
static bool
|
|
|
|
|
always_available(const _mesa_glsl_parse_state *)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
void
|
|
|
|
|
ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body)
|
2010-04-21 17:52:36 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *type_expr;
|
|
|
|
|
s_list *paramlist;
|
|
|
|
|
s_list *body_list;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "signature", type_expr, paramlist, body_list };
|
|
|
|
|
if (!MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "Expected (signature <type> (parameters ...) "
|
|
|
|
|
"(<instruction> ...))");
|
2010-04-28 12:45:18 -07:00
|
|
|
return;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *return_type = read_type(type_expr);
|
2010-04-21 17:52:36 -07:00
|
|
|
if (return_type == NULL)
|
2010-04-28 12:45:18 -07:00
|
|
|
return;
|
2010-04-21 17:52:36 -07:00
|
|
|
|
|
|
|
|
s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head());
|
|
|
|
|
if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(paramlist, "Expected (parameters ...)");
|
2010-04-28 12:45:18 -07:00
|
|
|
return;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2010-04-28 12:45:18 -07:00
|
|
|
// Read the parameters list into a temporary place.
|
|
|
|
|
exec_list hir_parameters;
|
2011-01-01 01:17:59 -08:00
|
|
|
state->symbols->push_scope();
|
2010-04-21 18:14:06 -07:00
|
|
|
|
2014-01-10 17:08:33 -08:00
|
|
|
/* Skip over the "parameters" tag. */
|
2016-06-27 14:42:57 -07:00
|
|
|
exec_node *node = paramlist->subexpressions.get_head_raw()->next;
|
2014-01-10 17:08:33 -08:00
|
|
|
for (/* nothing */; !node->is_tail_sentinel(); node = node->next) {
|
|
|
|
|
ir_variable *var = read_declaration((s_expression *) node);
|
2010-04-28 12:45:18 -07:00
|
|
|
if (var == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
hir_parameters.push_tail(var);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-30 23:11:55 -07:00
|
|
|
ir_function_signature *sig =
|
|
|
|
|
f->exact_matching_signature(state, &hir_parameters);
|
2010-08-11 16:53:52 -07:00
|
|
|
if (sig == NULL && skip_body) {
|
|
|
|
|
/* If scanning for prototypes, generate a new signature. */
|
glsl: Store a predicate for whether a built-in signature is available.
For the upcoming built-in function rewrite, we'll need to be able to
answer "Is this built-in function signature available?".
This is actually a somewhat complex question, since it depends on the
language version, GLSL vs. GLSL ES, enabled extensions, and the current
shader stage.
Storing such a set of constraints in a structure would be painful, so
instead we store a function pointer. When creating a signature, we
simply point to a predicate that inspects _mesa_glsl_parse_state and
answers whether the signature is available in the current shader.
Unfortunately, IR reader doesn't actually know when built-in functions
are available, so this patch makes it lie and say that they're always
present. This allows us to hook up the new functionality; it just won't
be useful until real data is populated. In the meantime, the existing
profile mechanism ensures built-ins are available in the right places.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-08-30 16:00:43 -07:00
|
|
|
/* ir_reader doesn't know what languages support a given built-in, so
|
|
|
|
|
* just say that they're always available. For now, other mechanisms
|
|
|
|
|
* guarantee the right built-ins are available.
|
|
|
|
|
*/
|
|
|
|
|
sig = new(mem_ctx) ir_function_signature(return_type, always_available);
|
2010-08-11 16:53:52 -07:00
|
|
|
f->add_signature(sig);
|
|
|
|
|
} else if (sig != NULL) {
|
2010-04-28 12:45:18 -07:00
|
|
|
const char *badvar = sig->qualifiers_match(&hir_parameters);
|
|
|
|
|
if (badvar != NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "function `%s' parameter `%s' qualifiers "
|
2010-04-28 12:45:18 -07:00
|
|
|
"don't match prototype", f->name, badvar);
|
|
|
|
|
return;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2010-04-28 12:45:18 -07:00
|
|
|
if (sig->return_type != return_type) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "function `%s' return type doesn't "
|
2010-04-28 12:45:18 -07:00
|
|
|
"match prototype", f->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-08-11 16:53:52 -07:00
|
|
|
/* No prototype for this body exists - skip it. */
|
2011-01-01 01:17:59 -08:00
|
|
|
state->symbols->pop_scope();
|
2010-08-11 16:53:52 -07:00
|
|
|
return;
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
2010-08-11 16:53:52 -07:00
|
|
|
assert(sig != NULL);
|
2010-04-21 17:52:36 -07:00
|
|
|
|
2010-04-28 12:45:18 -07:00
|
|
|
sig->replace_parameters(&hir_parameters);
|
|
|
|
|
|
2010-08-12 13:17:53 -07:00
|
|
|
if (!skip_body && !body_list->subexpressions.is_empty()) {
|
2010-04-28 12:45:18 -07:00
|
|
|
if (sig->is_defined) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "function %s redefined", f->name);
|
2010-04-28 12:45:18 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
state->current_function = sig;
|
|
|
|
|
read_instructions(&sig->body, body_list, NULL);
|
|
|
|
|
state->current_function = NULL;
|
2010-04-28 23:17:58 -07:00
|
|
|
sig->is_defined = true;
|
2010-04-28 12:45:18 -07:00
|
|
|
}
|
2010-04-21 18:14:06 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
state->symbols->pop_scope();
|
2010-04-21 17:52:36 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
void
|
|
|
|
|
ir_reader::read_instructions(exec_list *instructions, s_expression *expr,
|
|
|
|
|
ir_loop *loop_ctx)
|
2010-04-10 01:45:08 -07:00
|
|
|
{
|
|
|
|
|
// Read in a list of instructions
|
|
|
|
|
s_list *list = SX_AS_LIST(expr);
|
|
|
|
|
if (list == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
|
2010-04-10 01:45:08 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(s_expression, sub, &list->subexpressions) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_instruction *ir = read_instruction(sub, loop_ctx);
|
2010-09-04 01:55:55 -07:00
|
|
|
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.
|
|
|
|
|
*/
|
2011-01-01 01:17:59 -08:00
|
|
|
if (state->current_function == NULL && ir->as_variable() != NULL)
|
2010-09-04 01:55:55 -07:00
|
|
|
instructions->push_head(ir);
|
|
|
|
|
else
|
|
|
|
|
instructions->push_tail(ir);
|
|
|
|
|
}
|
2010-04-10 01:45:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_instruction *
|
|
|
|
|
ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
|
2010-04-09 17:40:51 -07:00
|
|
|
{
|
2010-04-12 16:02:48 -07:00
|
|
|
s_symbol *symbol = SX_AS_SYMBOL(expr);
|
|
|
|
|
if (symbol != NULL) {
|
|
|
|
|
if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL)
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break);
|
2010-04-12 16:02:48 -07:00
|
|
|
if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL)
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
|
2010-04-12 16:02:48 -07:00
|
|
|
}
|
|
|
|
|
|
2010-04-09 17:40:51 -07:00
|
|
|
s_list *list = SX_AS_LIST(expr);
|
2010-07-07 15:23:27 -07:00
|
|
|
if (list == NULL || list->subexpressions.is_empty()) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "Invalid instruction.\n");
|
2010-04-09 17:40:51 -07:00
|
|
|
return NULL;
|
2010-07-07 15:23:27 -07:00
|
|
|
}
|
2010-04-09 17:40:51 -07:00
|
|
|
|
|
|
|
|
s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
|
|
|
|
|
if (tag == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected instruction tag");
|
2010-04-09 17:40:51 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_instruction *inst = NULL;
|
2010-04-12 14:25:41 -07:00
|
|
|
if (strcmp(tag->value(), "declare") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_declaration(list);
|
2010-07-22 16:40:35 -07:00
|
|
|
} else if (strcmp(tag->value(), "assign") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_assignment(list);
|
2010-04-12 14:25:41 -07:00
|
|
|
} else if (strcmp(tag->value(), "if") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_if(list, loop_ctx);
|
2010-04-12 15:48:27 -07:00
|
|
|
} else if (strcmp(tag->value(), "loop") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_loop(list);
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
} else if (strcmp(tag->value(), "call") == 0) {
|
|
|
|
|
inst = read_call(list);
|
2010-04-12 14:25:41 -07:00
|
|
|
} else if (strcmp(tag->value(), "return") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_return(list);
|
2010-04-21 18:14:06 -07:00
|
|
|
} else if (strcmp(tag->value(), "function") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_function(list, false);
|
2013-02-15 09:26:35 -06:00
|
|
|
} else if (strcmp(tag->value(), "emit-vertex") == 0) {
|
|
|
|
|
inst = read_emit_vertex(list);
|
|
|
|
|
} else if (strcmp(tag->value(), "end-primitive") == 0) {
|
|
|
|
|
inst = read_end_primitive(list);
|
2014-09-07 19:24:15 +12:00
|
|
|
} else if (strcmp(tag->value(), "barrier") == 0) {
|
|
|
|
|
inst = read_barrier(list);
|
2010-04-12 14:25:41 -07:00
|
|
|
} else {
|
2011-01-01 01:17:59 -08:00
|
|
|
inst = read_rvalue(list);
|
2010-04-12 14:25:41 -07:00
|
|
|
if (inst == NULL)
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading instruction");
|
2010-04-12 14:25:41 -07:00
|
|
|
}
|
2010-04-09 17:40:51 -07:00
|
|
|
return inst;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_variable *
|
|
|
|
|
ir_reader::read_declaration(s_expression *expr)
|
2010-04-09 17:40:51 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_list *s_quals;
|
|
|
|
|
s_expression *s_type;
|
|
|
|
|
s_symbol *s_name;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "declare", s_quals, s_type, s_name };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (declare (<qualifiers>) <type> <name>)");
|
2010-04-09 17:40:51 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *type = read_type(s_type);
|
2010-04-09 17:40:51 -07:00
|
|
|
if (type == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(),
|
|
|
|
|
ir_var_auto);
|
2010-04-09 17:40:51 -07:00
|
|
|
|
2014-06-24 22:11:04 -07:00
|
|
|
foreach_in_list(s_symbol, qualifier, &s_quals->subexpressions) {
|
|
|
|
|
if (!qualifier->is_symbol()) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "qualifier list must contain only symbols");
|
2010-04-09 17:40:51 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FINISHME: Check for duplicate/conflicting qualifiers.
|
|
|
|
|
if (strcmp(qualifier->value(), "centroid") == 0) {
|
2013-12-12 12:57:57 +02:00
|
|
|
var->data.centroid = 1;
|
2013-11-29 21:26:10 +13:00
|
|
|
} else if (strcmp(qualifier->value(), "sample") == 0) {
|
2013-12-12 12:57:57 +02:00
|
|
|
var->data.sample = 1;
|
2014-03-05 13:43:17 +01:00
|
|
|
} else if (strcmp(qualifier->value(), "patch") == 0) {
|
|
|
|
|
var->data.patch = 1;
|
2018-09-04 11:42:04 +03:00
|
|
|
} else if (strcmp(qualifier->value(), "explicit_invariant") == 0) {
|
|
|
|
|
var->data.explicit_invariant = true;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "invariant") == 0) {
|
2018-09-04 11:42:04 +03:00
|
|
|
var->data.invariant = true;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "uniform") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_uniform;
|
2015-05-13 10:41:55 +02:00
|
|
|
} else if (strcmp(qualifier->value(), "shader_storage") == 0) {
|
|
|
|
|
var->data.mode = ir_var_shader_storage;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "auto") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_auto;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "in") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_function_in;
|
2013-01-11 14:39:32 -08:00
|
|
|
} else if (strcmp(qualifier->value(), "shader_in") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_shader_in;
|
2011-01-12 15:37:37 -08:00
|
|
|
} else if (strcmp(qualifier->value(), "const_in") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_const_in;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "out") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_function_out;
|
2013-01-11 14:39:32 -08:00
|
|
|
} else if (strcmp(qualifier->value(), "shader_out") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_shader_out;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "inout") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_function_inout;
|
2012-04-18 14:43:12 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "temporary") == 0) {
|
2013-12-12 13:51:01 +02:00
|
|
|
var->data.mode = ir_var_temporary;
|
2014-06-10 08:45:44 +02:00
|
|
|
} else if (strcmp(qualifier->value(), "stream1") == 0) {
|
|
|
|
|
var->data.stream = 1;
|
|
|
|
|
} else if (strcmp(qualifier->value(), "stream2") == 0) {
|
|
|
|
|
var->data.stream = 2;
|
|
|
|
|
} else if (strcmp(qualifier->value(), "stream3") == 0) {
|
|
|
|
|
var->data.stream = 3;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "smooth") == 0) {
|
2016-07-07 02:02:38 -07:00
|
|
|
var->data.interpolation = INTERP_MODE_SMOOTH;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "flat") == 0) {
|
2016-07-07 02:02:38 -07:00
|
|
|
var->data.interpolation = INTERP_MODE_FLAT;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else if (strcmp(qualifier->value(), "noperspective") == 0) {
|
2016-07-07 02:02:38 -07:00
|
|
|
var->data.interpolation = INTERP_MODE_NOPERSPECTIVE;
|
2010-04-09 17:40:51 -07:00
|
|
|
} else {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "unknown qualifier: %s", qualifier->value());
|
2010-04-09 17:40:51 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the variable to the symbol table
|
2011-01-01 01:17:59 -08:00
|
|
|
state->symbols->add_variable(var);
|
2010-04-09 17:40:51 -07:00
|
|
|
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_if *
|
|
|
|
|
ir_reader::read_if(s_expression *expr, ir_loop *loop_ctx)
|
2010-04-10 01:45:08 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_cond;
|
|
|
|
|
s_expression *s_then;
|
|
|
|
|
s_expression *s_else;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "if", s_cond, s_then, s_else };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (if <condition> (<then>...) (<else>...))");
|
2010-04-10 01:45:08 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *condition = read_rvalue(s_cond);
|
2010-04-10 01:45:08 -07:00
|
|
|
if (condition == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading condition of (if ...)");
|
2010-04-10 01:45:08 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_if *iff = new(mem_ctx) ir_if(condition);
|
2010-04-10 01:45:08 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
read_instructions(&iff->then_instructions, s_then, loop_ctx);
|
|
|
|
|
read_instructions(&iff->else_instructions, s_else, loop_ctx);
|
|
|
|
|
if (state->error) {
|
2010-04-10 01:45:08 -07:00
|
|
|
delete iff;
|
|
|
|
|
iff = NULL;
|
|
|
|
|
}
|
|
|
|
|
return iff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_loop *
|
|
|
|
|
ir_reader::read_loop(s_expression *expr)
|
2010-04-12 15:48:27 -07:00
|
|
|
{
|
2013-11-29 00:52:11 -08:00
|
|
|
s_expression *s_body;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
2013-11-29 00:52:11 -08:00
|
|
|
s_pattern loop_pat[] = { "loop", s_body };
|
2013-11-28 08:13:41 -08:00
|
|
|
if (!MATCH(expr, loop_pat)) {
|
2013-11-29 00:52:11 -08:00
|
|
|
ir_read_error(expr, "expected (loop <body>)");
|
2010-04-12 15:48:27 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_loop *loop = new(mem_ctx) ir_loop;
|
2013-11-28 08:13:41 -08:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
read_instructions(&loop->body_instructions, s_body, loop);
|
|
|
|
|
if (state->error) {
|
2010-04-12 15:48:27 -07:00
|
|
|
delete loop;
|
|
|
|
|
loop = NULL;
|
|
|
|
|
}
|
|
|
|
|
return loop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_return *
|
|
|
|
|
ir_reader::read_return(s_expression *expr)
|
2010-04-09 17:56:22 -07:00
|
|
|
{
|
2010-12-31 02:03:21 -08:00
|
|
|
s_expression *s_retval;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
2011-06-29 15:30:40 -07:00
|
|
|
s_pattern return_value_pat[] = { "return", s_retval};
|
|
|
|
|
s_pattern return_void_pat[] = { "return" };
|
|
|
|
|
if (MATCH(expr, return_value_pat)) {
|
|
|
|
|
ir_rvalue *retval = read_rvalue(s_retval);
|
|
|
|
|
if (retval == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading return value");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return new(mem_ctx) ir_return(retval);
|
|
|
|
|
} else if (MATCH(expr, return_void_pat)) {
|
|
|
|
|
return new(mem_ctx) ir_return;
|
|
|
|
|
} else {
|
|
|
|
|
ir_read_error(expr, "expected (return <rvalue>) or (return)");
|
2010-04-09 17:56:22 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *
|
|
|
|
|
ir_reader::read_rvalue(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
|
|
|
|
s_list *list = SX_AS_LIST(expr);
|
|
|
|
|
if (list == NULL || list->subexpressions.is_empty())
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
|
|
|
|
|
if (tag == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected rvalue tag");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *rvalue = read_dereference(list);
|
|
|
|
|
if (rvalue != NULL || state->error)
|
2010-05-26 17:52:44 -07:00
|
|
|
return rvalue;
|
|
|
|
|
else if (strcmp(tag->value(), "swiz") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
rvalue = read_swizzle(list);
|
2010-04-12 14:27:39 -07:00
|
|
|
} else if (strcmp(tag->value(), "expression") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
rvalue = read_expression(list);
|
2010-04-12 14:27:39 -07:00
|
|
|
} else if (strcmp(tag->value(), "constant") == 0) {
|
2011-01-01 01:17:59 -08:00
|
|
|
rvalue = read_constant(list);
|
2010-04-12 14:27:39 -07:00
|
|
|
} else {
|
2011-01-01 01:17:59 -08:00
|
|
|
rvalue = read_texture(list);
|
|
|
|
|
if (rvalue == NULL && !state->error)
|
|
|
|
|
ir_read_error(expr, "unrecognized rvalue tag: %s", tag->value());
|
2010-04-12 14:27:39 -07:00
|
|
|
}
|
2010-04-07 17:24:44 -07:00
|
|
|
|
|
|
|
|
return rvalue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_assignment *
|
|
|
|
|
ir_reader::read_assignment(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
2011-01-01 03:37:02 -08:00
|
|
|
s_expression *cond_expr = NULL;
|
|
|
|
|
s_expression *lhs_expr, *rhs_expr;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_list *mask_list;
|
|
|
|
|
|
2011-01-01 03:37:02 -08:00
|
|
|
s_pattern pat4[] = { "assign", mask_list, lhs_expr, rhs_expr };
|
|
|
|
|
s_pattern pat5[] = { "assign", cond_expr, mask_list, lhs_expr, rhs_expr };
|
|
|
|
|
if (!MATCH(expr, pat4) && !MATCH(expr, pat5)) {
|
2022-01-14 17:55:21 -08:00
|
|
|
ir_read_error(expr, "expected (assign (<write mask>) <lhs> <rhs>)");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 03:37:02 -08:00
|
|
|
if (cond_expr != NULL) {
|
2022-01-14 17:55:21 -08:00
|
|
|
ir_rvalue *condition = read_rvalue(cond_expr);
|
|
|
|
|
if (condition == NULL)
|
|
|
|
|
ir_read_error(NULL, "when reading condition of assignment");
|
|
|
|
|
else
|
|
|
|
|
ir_read_error(expr, "conditional assignemnts are deprecated");
|
|
|
|
|
|
|
|
|
|
return NULL;
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2010-09-02 23:54:40 -07:00
|
|
|
unsigned mask = 0;
|
|
|
|
|
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_symbol *mask_symbol;
|
|
|
|
|
s_pattern mask_pat[] = { mask_symbol };
|
|
|
|
|
if (MATCH(mask_list, mask_pat)) {
|
2010-09-02 23:54:40 -07:00
|
|
|
const char *mask_str = mask_symbol->value();
|
|
|
|
|
unsigned mask_length = strlen(mask_str);
|
|
|
|
|
if (mask_length > 4) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "invalid write mask: %s", mask_str);
|
2010-09-02 23:54:40 -07:00
|
|
|
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') {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "write mask contains invalid character: %c",
|
2010-09-02 23:54:40 -07:00
|
|
|
mask_str[i]);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
mask |= 1 << idx_map[mask_str[i] - 'w'];
|
|
|
|
|
}
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
} else if (!mask_list->subexpressions.is_empty()) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(mask_list, "expected () or (<write mask>)");
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
2010-09-02 23:54:40 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_dereference *lhs = read_dereference(lhs_expr);
|
2010-04-07 17:24:44 -07:00
|
|
|
if (lhs == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading left-hand side of assignment");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *rhs = read_rvalue(rhs_expr);
|
2010-04-07 17:24:44 -07:00
|
|
|
if (rhs == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading right-hand side of assignment");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-14 22:21:26 -08:00
|
|
|
if (mask == 0 && (glsl_type_is_vector(lhs->type) || glsl_type_is_scalar(lhs->type))) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "non-zero write mask required.");
|
2010-09-02 23:54:40 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 17:55:21 -08:00
|
|
|
return new(mem_ctx) ir_assignment(lhs, rhs, mask);
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_call *
|
|
|
|
|
ir_reader::read_call(s_expression *expr)
|
2010-04-28 12:54:21 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_symbol *name;
|
|
|
|
|
s_list *params;
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
s_list *s_return = NULL;
|
2010-04-28 12:54:21 -07:00
|
|
|
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
ir_dereference_variable *return_deref = NULL;
|
|
|
|
|
|
|
|
|
|
s_pattern void_pat[] = { "call", name, params };
|
|
|
|
|
s_pattern non_void_pat[] = { "call", name, s_return, params };
|
|
|
|
|
if (MATCH(expr, non_void_pat)) {
|
|
|
|
|
return_deref = read_var_ref(s_return);
|
|
|
|
|
if (return_deref == NULL) {
|
|
|
|
|
ir_read_error(s_return, "when reading a call's return storage");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else if (!MATCH(expr, void_pat)) {
|
|
|
|
|
ir_read_error(expr, "expected (call <name> [<deref>] (<param> ...))");
|
2010-04-28 12:54:21 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exec_list parameters;
|
|
|
|
|
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(s_expression, e, ¶ms->subexpressions) {
|
|
|
|
|
ir_rvalue *param = read_rvalue(e);
|
2010-04-28 12:54:21 -07:00
|
|
|
if (param == NULL) {
|
2014-06-24 21:34:05 -07:00
|
|
|
ir_read_error(e, "when reading parameter to function call");
|
2010-04-28 12:54:21 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
parameters.push_tail(param);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_function *f = state->symbols->get_function(name->value());
|
2010-04-28 12:54:21 -07:00
|
|
|
if (f == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "found call to undefined function %s",
|
2010-04-28 12:54:21 -07:00
|
|
|
name->value());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 14:05:40 -07:00
|
|
|
ir_function_signature *callee =
|
|
|
|
|
f->matching_signature(state, ¶meters, true);
|
2010-04-28 12:54:21 -07:00
|
|
|
if (callee == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "couldn't find matching signature for function "
|
2010-04-28 12:54:21 -07:00
|
|
|
"%s", name->value());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-12 12:49:24 -08:00
|
|
|
if (callee->return_type == &glsl_type_builtin_void && return_deref) {
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
ir_read_error(expr, "call has return value storage but void type");
|
|
|
|
|
return NULL;
|
2023-12-12 12:49:24 -08:00
|
|
|
} else if (callee->return_type != &glsl_type_builtin_void && !return_deref) {
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 15:56:37 -07:00
|
|
|
ir_read_error(expr, "call has non-void type but no return value storage");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new(mem_ctx) ir_call(callee, return_deref, ¶meters);
|
2010-04-28 12:54:21 -07:00
|
|
|
}
|
2010-04-07 17:24:44 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_expression *
|
|
|
|
|
ir_reader::read_expression(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_type;
|
|
|
|
|
s_symbol *s_op;
|
2013-04-09 16:43:14 -07:00
|
|
|
s_expression *s_arg[4] = {NULL};
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
2012-12-01 23:49:19 -08:00
|
|
|
s_pattern pat[] = { "expression", s_type, s_op, s_arg[0] };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!PARTIAL_MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (expression <type> <operator> "
|
2013-04-09 16:43:14 -07:00
|
|
|
"<operand> [<operand>] [<operand>] [<operand>])");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2012-12-01 23:49:19 -08:00
|
|
|
s_arg[1] = (s_expression *) s_arg[0]->next; // may be tail sentinel
|
|
|
|
|
s_arg[2] = (s_expression *) s_arg[1]->next; // may be tail sentinel or NULL
|
2013-04-09 16:43:14 -07:00
|
|
|
if (s_arg[2])
|
|
|
|
|
s_arg[3] = (s_expression *) s_arg[2]->next; // may be tail sentinel or NULL
|
2010-04-07 17:24:44 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *type = read_type(s_type);
|
2010-04-07 17:24:44 -07:00
|
|
|
if (type == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Read the operator */
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
ir_expression_operation op = ir_expression::get_operator(s_op->value());
|
2010-04-07 17:24:44 -07:00
|
|
|
if (op == (ir_expression_operation) -1) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "invalid operator: %s", s_op->value());
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-07-08 12:21:00 -07:00
|
|
|
|
|
|
|
|
/* Skip "expression" <type> <operation> by subtracting 3. */
|
|
|
|
|
int num_operands = (int) ((s_list *) expr)->subexpressions.length() - 3;
|
2012-12-01 23:49:19 -08:00
|
|
|
|
|
|
|
|
int expected_operands = ir_expression::get_num_operands(op);
|
|
|
|
|
if (num_operands != expected_operands) {
|
|
|
|
|
ir_read_error(expr, "found %d expression operands, expected %d",
|
|
|
|
|
num_operands, expected_operands);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 16:43:14 -07:00
|
|
|
ir_rvalue *arg[4] = {NULL};
|
2012-12-01 23:49:19 -08:00
|
|
|
for (int i = 0; i < num_operands; i++) {
|
|
|
|
|
arg[i] = read_rvalue(s_arg[i]);
|
|
|
|
|
if (arg[i] == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading operand #%d of %s", i, s_op->value());
|
|
|
|
|
return NULL;
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 16:43:14 -07:00
|
|
|
return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2], arg[3]);
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_swizzle *
|
|
|
|
|
ir_reader::read_swizzle(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_symbol *swiz;
|
|
|
|
|
s_expression *sub;
|
2010-04-07 17:24:44 -07:00
|
|
|
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_pattern pat[] = { "swiz", swiz, sub };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (swiz <swizzle> <rvalue>)");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 23:15:08 -07:00
|
|
|
if (strlen(swiz->value()) > 4) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected a valid swizzle; found %s", swiz->value());
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *rvalue = read_rvalue(sub);
|
2010-04-07 17:24:44 -07:00
|
|
|
if (rvalue == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2010-04-28 13:16:31 -07:00
|
|
|
ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(),
|
|
|
|
|
rvalue->type->vector_elements);
|
|
|
|
|
if (ir == NULL)
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "invalid swizzle");
|
2010-04-28 13:16:31 -07:00
|
|
|
|
|
|
|
|
return ir;
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_constant *
|
|
|
|
|
ir_reader::read_constant(s_expression *expr)
|
2010-04-07 17:24:44 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *type_expr;
|
|
|
|
|
s_list *values;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "constant", type_expr, values };
|
2010-12-31 02:03:21 -08:00
|
|
|
if (!MATCH(expr, pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (constant <type> (...))");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
const glsl_type *type = read_type(type_expr);
|
2010-04-07 17:24:44 -07:00
|
|
|
if (type == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (values == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "expected (constant <type> (...))");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-14 22:21:26 -08:00
|
|
|
if (glsl_type_is_array(type)) {
|
2010-12-31 01:48:02 -08:00
|
|
|
unsigned elements_supplied = 0;
|
2010-07-20 01:53:07 -07:00
|
|
|
exec_list elements;
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(s_expression, elt, &values->subexpressions) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_constant *ir_elt = read_constant(elt);
|
2010-07-20 01:53:07 -07:00
|
|
|
if (ir_elt == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
elements.push_tail(ir_elt);
|
2010-12-31 01:48:02 -08:00
|
|
|
elements_supplied++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (elements_supplied != type->length) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(values, "expected exactly %u array elements, "
|
2010-12-31 01:48:02 -08:00
|
|
|
"given %u", type->length, elements_supplied);
|
|
|
|
|
return NULL;
|
2010-07-20 01:53:07 -07:00
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_constant(type, &elements);
|
2010-07-20 01:53:07 -07:00
|
|
|
}
|
|
|
|
|
|
2010-08-29 11:48:02 -07:00
|
|
|
ir_constant_data data = { { 0 } };
|
2010-04-07 17:24:44 -07:00
|
|
|
|
|
|
|
|
// Read in list of values (at most 16).
|
2011-09-07 11:44:35 -06:00
|
|
|
unsigned k = 0;
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(s_expression, expr, &values->subexpressions) {
|
2010-04-07 17:24:44 -07:00
|
|
|
if (k >= 16) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(values, "expected at most 16 numbers");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-14 22:21:26 -08:00
|
|
|
if (glsl_type_is_float(type)) {
|
2010-04-07 17:24:44 -07:00
|
|
|
s_number *value = SX_AS_NUMBER(expr);
|
|
|
|
|
if (value == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(values, "expected numbers");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-06-11 16:43:42 -07:00
|
|
|
data.f[k] = value->fvalue();
|
2010-04-07 17:24:44 -07:00
|
|
|
} else {
|
|
|
|
|
s_int *value = SX_AS_INT(expr);
|
|
|
|
|
if (value == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(values, "expected integers");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-25 12:55:54 -07:00
|
|
|
switch (type->base_type) {
|
2010-04-07 17:24:44 -07:00
|
|
|
case GLSL_TYPE_UINT: {
|
2010-06-11 16:43:42 -07:00
|
|
|
data.u[k] = value->value();
|
2010-04-07 17:24:44 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GLSL_TYPE_INT: {
|
2010-06-11 16:43:42 -07:00
|
|
|
data.i[k] = value->value();
|
2010-04-07 17:24:44 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GLSL_TYPE_BOOL: {
|
2010-06-11 16:43:42 -07:00
|
|
|
data.b[k] = value->value();
|
2010-04-07 17:24:44 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(values, "unsupported constant type");
|
2010-04-07 17:24:44 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
++k;
|
|
|
|
|
}
|
2023-12-14 22:21:26 -08:00
|
|
|
if (k != glsl_get_components(type)) {
|
2011-09-07 11:44:35 -06:00
|
|
|
ir_read_error(values, "expected %u constant values, found %u",
|
2023-12-14 22:21:26 -08:00
|
|
|
glsl_get_components(type), k);
|
2011-09-05 12:03:29 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-06-11 16:43:42 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_constant(type, &data);
|
2010-04-07 17:24:44 -07:00
|
|
|
}
|
2010-04-12 14:27:39 -07:00
|
|
|
|
2011-09-22 14:29:53 -07:00
|
|
|
ir_dereference_variable *
|
|
|
|
|
ir_reader::read_var_ref(s_expression *expr)
|
2010-05-26 17:52:44 -07:00
|
|
|
{
|
2010-12-31 02:17:58 -08:00
|
|
|
s_symbol *s_var;
|
|
|
|
|
s_pattern var_pat[] = { "var_ref", s_var };
|
|
|
|
|
|
|
|
|
|
if (MATCH(expr, var_pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_variable *var = state->symbols->get_variable(s_var->value());
|
2010-12-31 02:17:58 -08:00
|
|
|
if (var == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(expr, "undeclared variable: %s", s_var->value());
|
2010-12-31 02:17:58 -08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_dereference_variable(var);
|
2011-09-22 14:29:53 -07:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_dereference *
|
|
|
|
|
ir_reader::read_dereference(s_expression *expr)
|
|
|
|
|
{
|
|
|
|
|
s_expression *s_subject;
|
|
|
|
|
s_expression *s_index;
|
|
|
|
|
s_symbol *s_field;
|
|
|
|
|
|
|
|
|
|
s_pattern array_pat[] = { "array_ref", s_subject, s_index };
|
|
|
|
|
s_pattern record_pat[] = { "record_ref", s_subject, s_field };
|
|
|
|
|
|
|
|
|
|
ir_dereference_variable *var_ref = read_var_ref(expr);
|
|
|
|
|
if (var_ref != NULL) {
|
|
|
|
|
return var_ref;
|
2010-12-31 02:17:58 -08:00
|
|
|
} else if (MATCH(expr, array_pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *subject = read_rvalue(s_subject);
|
2010-12-31 02:17:58 -08:00
|
|
|
if (subject == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading the subject of an array_ref");
|
2010-12-31 02:17:58 -08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-05-26 15:20:59 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *idx = read_rvalue(s_index);
|
2013-06-06 23:07:30 -07:00
|
|
|
if (idx == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading the index of an array_ref");
|
2010-12-31 02:17:58 -08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_dereference_array(subject, idx);
|
2010-12-31 02:17:58 -08:00
|
|
|
} else if (MATCH(expr, record_pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_rvalue *subject = read_rvalue(s_subject);
|
2010-12-31 02:17:58 -08:00
|
|
|
if (subject == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading the subject of a record_ref");
|
2010-12-31 02:17:58 -08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
return new(mem_ctx) ir_dereference_record(subject, s_field->value());
|
2010-05-26 15:20:59 -07:00
|
|
|
}
|
2010-12-31 02:17:58 -08:00
|
|
|
return NULL;
|
2010-04-12 14:27:39 -07:00
|
|
|
}
|
2010-05-26 17:55:10 -07:00
|
|
|
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_texture *
|
|
|
|
|
ir_reader::read_texture(s_expression *expr)
|
2010-05-26 17:55:10 -07:00
|
|
|
{
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_symbol *tag = NULL;
|
2021-12-28 22:14:11 +08:00
|
|
|
s_expression *s_sparse = NULL;
|
2011-02-25 14:29:36 -08:00
|
|
|
s_expression *s_type = NULL;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_sampler = NULL;
|
|
|
|
|
s_expression *s_coord = NULL;
|
2011-01-08 23:49:23 -08:00
|
|
|
s_expression *s_offset = NULL;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_proj = NULL;
|
|
|
|
|
s_list *s_shadow = NULL;
|
2022-01-06 14:25:07 +08:00
|
|
|
s_list *s_clamp = NULL;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_expression *s_lod = NULL;
|
2012-12-21 21:33:37 +13:00
|
|
|
s_expression *s_sample_index = NULL;
|
2013-10-05 18:26:56 +13:00
|
|
|
s_expression *s_component = NULL;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
2011-01-25 13:09:57 -07:00
|
|
|
ir_texture_opcode op = ir_tex; /* silence warning */
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
|
|
|
|
s_pattern tex_pattern[] =
|
2022-01-06 14:25:07 +08:00
|
|
|
{ "tex", s_type, s_sampler, s_coord, s_sparse, s_offset, s_proj, s_shadow, s_clamp };
|
|
|
|
|
s_pattern txb_pattern[] =
|
|
|
|
|
{ "txb", s_type, s_sampler, s_coord, s_sparse, s_offset, s_proj, s_shadow, s_clamp, s_lod };
|
|
|
|
|
s_pattern txd_pattern[] =
|
|
|
|
|
{ "txd", s_type, s_sampler, s_coord, s_sparse, s_offset, s_proj, s_shadow, s_clamp, s_lod };
|
2012-09-23 19:50:41 +10:00
|
|
|
s_pattern lod_pattern[] =
|
|
|
|
|
{ "lod", s_type, s_sampler, s_coord };
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_pattern txf_pattern[] =
|
2021-12-28 22:14:11 +08:00
|
|
|
{ "txf", s_type, s_sampler, s_coord, s_sparse, s_offset, s_lod };
|
2012-12-21 21:33:37 +13:00
|
|
|
s_pattern txf_ms_pattern[] =
|
2021-12-28 22:14:11 +08:00
|
|
|
{ "txf_ms", s_type, s_sampler, s_coord, s_sparse, s_sample_index };
|
2011-02-25 14:45:33 -08:00
|
|
|
s_pattern txs_pattern[] =
|
|
|
|
|
{ "txs", s_type, s_sampler, s_lod };
|
2012-12-24 00:57:37 +01:00
|
|
|
s_pattern tg4_pattern[] =
|
2021-12-28 22:14:11 +08:00
|
|
|
{ "tg4", s_type, s_sampler, s_coord, s_sparse, s_offset, s_component };
|
2013-09-26 19:37:30 +12:00
|
|
|
s_pattern query_levels_pattern[] =
|
|
|
|
|
{ "query_levels", s_type, s_sampler };
|
2015-08-27 23:03:46 -04:00
|
|
|
s_pattern texture_samples_pattern[] =
|
|
|
|
|
{ "samples", s_type, s_sampler };
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_pattern other_pattern[] =
|
2021-12-28 22:14:11 +08:00
|
|
|
{ tag, s_type, s_sampler, s_coord, s_sparse, s_offset, s_proj, s_shadow, s_lod };
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
|
2012-09-23 19:50:41 +10:00
|
|
|
if (MATCH(expr, lod_pattern)) {
|
|
|
|
|
op = ir_lod;
|
|
|
|
|
} else if (MATCH(expr, tex_pattern)) {
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
op = ir_tex;
|
2022-01-06 14:25:07 +08:00
|
|
|
} else if (MATCH(expr, txb_pattern)) {
|
|
|
|
|
op = ir_txb;
|
|
|
|
|
} else if (MATCH(expr, txd_pattern)) {
|
|
|
|
|
op = ir_txd;
|
2010-12-31 02:03:21 -08:00
|
|
|
} else if (MATCH(expr, txf_pattern)) {
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
op = ir_txf;
|
2012-12-21 21:33:37 +13:00
|
|
|
} else if (MATCH(expr, txf_ms_pattern)) {
|
|
|
|
|
op = ir_txf_ms;
|
2011-02-25 14:45:33 -08:00
|
|
|
} else if (MATCH(expr, txs_pattern)) {
|
|
|
|
|
op = ir_txs;
|
2012-12-24 00:57:37 +01:00
|
|
|
} else if (MATCH(expr, tg4_pattern)) {
|
|
|
|
|
op = ir_tg4;
|
2013-09-26 19:37:30 +12:00
|
|
|
} else if (MATCH(expr, query_levels_pattern)) {
|
|
|
|
|
op = ir_query_levels;
|
2015-08-27 23:03:46 -04:00
|
|
|
} else if (MATCH(expr, texture_samples_pattern)) {
|
|
|
|
|
op = ir_texture_samples;
|
2010-12-31 02:03:21 -08:00
|
|
|
} else if (MATCH(expr, other_pattern)) {
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
op = ir_texture::get_opcode(tag->value());
|
2014-11-21 14:53:20 -08:00
|
|
|
if (op == (ir_texture_opcode) -1)
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
2011-01-25 13:09:57 -07:00
|
|
|
} else {
|
2012-09-23 19:50:41 +10:00
|
|
|
ir_read_error(NULL, "unexpected texture pattern %s", tag->value());
|
2011-01-25 13:09:57 -07:00
|
|
|
return NULL;
|
2010-05-26 17:55:10 -07:00
|
|
|
}
|
|
|
|
|
|
2021-12-28 22:14:11 +08:00
|
|
|
bool is_sparse = false;
|
|
|
|
|
if (s_sparse) {
|
|
|
|
|
s_int *sparse = SX_AS_INT(s_sparse);
|
|
|
|
|
if (sparse == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading sparse");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
is_sparse = sparse->value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_texture *tex = new(mem_ctx) ir_texture(op, is_sparse);
|
2010-05-26 17:55:10 -07:00
|
|
|
|
2011-02-25 14:29:36 -08:00
|
|
|
// Read return type
|
|
|
|
|
const glsl_type *type = read_type(s_type);
|
|
|
|
|
if (type == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading type in (%s ...)",
|
|
|
|
|
tex->opcode_string());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-26 17:55:10 -07:00
|
|
|
// Read sampler (must be a deref)
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_dereference *sampler = read_dereference(s_sampler);
|
2010-06-03 15:07:34 -07:00
|
|
|
if (sampler == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading sampler in (%s ...)",
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
tex->opcode_string());
|
2010-05-26 17:55:10 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2021-12-28 22:14:11 +08:00
|
|
|
|
|
|
|
|
if (is_sparse) {
|
2023-12-14 22:21:26 -08:00
|
|
|
const glsl_type *texel = glsl_get_field_type(type, "texel");
|
2023-12-12 12:49:24 -08:00
|
|
|
if (texel == &glsl_type_builtin_error) {
|
2021-12-28 22:14:11 +08:00
|
|
|
ir_read_error(NULL, "invalid type for sparse texture");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
type = texel;
|
|
|
|
|
}
|
2011-02-25 14:29:36 -08:00
|
|
|
tex->set_sampler(sampler, type);
|
2010-05-26 17:55:10 -07:00
|
|
|
|
2011-02-25 14:45:33 -08:00
|
|
|
if (op != ir_txs) {
|
|
|
|
|
// Read coordinate (any rvalue)
|
|
|
|
|
tex->coordinate = read_rvalue(s_coord);
|
|
|
|
|
if (tex->coordinate == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading coordinate in (%s ...)",
|
|
|
|
|
tex->opcode_string());
|
2011-01-08 23:49:23 -08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-02-25 14:45:33 -08:00
|
|
|
|
2012-09-23 19:50:41 +10:00
|
|
|
if (op != ir_txf_ms && op != ir_lod) {
|
2012-12-21 21:33:37 +13:00
|
|
|
// Read texel offset - either 0 or an rvalue.
|
|
|
|
|
s_int *si_offset = SX_AS_INT(s_offset);
|
|
|
|
|
if (si_offset == NULL || si_offset->value() != 0) {
|
|
|
|
|
tex->offset = read_rvalue(s_offset);
|
|
|
|
|
if (tex->offset == NULL) {
|
|
|
|
|
ir_read_error(s_offset, "expected 0 or an expression");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-25 14:45:33 -08:00
|
|
|
}
|
2010-05-26 17:55:10 -07:00
|
|
|
}
|
|
|
|
|
|
2013-09-26 19:37:30 +12:00
|
|
|
if (op != ir_txf && op != ir_txf_ms &&
|
|
|
|
|
op != ir_txs && op != ir_lod && op != ir_tg4 &&
|
2015-08-27 23:03:46 -04:00
|
|
|
op != ir_query_levels && op != ir_texture_samples) {
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
s_int *proj_as_int = SX_AS_INT(s_proj);
|
2010-05-26 17:55:10 -07:00
|
|
|
if (proj_as_int && proj_as_int->value() == 1) {
|
|
|
|
|
tex->projector = NULL;
|
|
|
|
|
} else {
|
2011-01-01 01:17:59 -08:00
|
|
|
tex->projector = read_rvalue(s_proj);
|
2010-05-26 17:55:10 -07:00
|
|
|
if (tex->projector == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading projective divide in (%s ..)",
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
tex->opcode_string());
|
2010-05-26 17:55:10 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (s_shadow->subexpressions.is_empty()) {
|
2016-12-12 08:32:38 -05:00
|
|
|
tex->shadow_comparator = NULL;
|
2010-05-26 17:55:10 -07:00
|
|
|
} else {
|
2016-12-12 08:32:38 -05:00
|
|
|
tex->shadow_comparator = read_rvalue(s_shadow);
|
|
|
|
|
if (tex->shadow_comparator == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading shadow comparator in (%s ..)",
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
tex->opcode_string());
|
2010-05-26 17:55:10 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
}
|
2010-05-26 17:55:10 -07:00
|
|
|
|
2022-01-06 14:25:07 +08:00
|
|
|
if (op == ir_tex || op == ir_txb || op == ir_txd) {
|
|
|
|
|
if (s_clamp->subexpressions.is_empty()) {
|
|
|
|
|
tex->clamp = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
tex->clamp = read_rvalue(s_clamp);
|
|
|
|
|
if (tex->clamp == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading clamp in (%s ..)",
|
|
|
|
|
tex->opcode_string());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
switch (op) {
|
|
|
|
|
case ir_txb:
|
2011-01-01 01:17:59 -08:00
|
|
|
tex->lod_info.bias = read_rvalue(s_lod);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (tex->lod_info.bias == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading LOD bias in (txb ...)");
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ir_txl:
|
|
|
|
|
case ir_txf:
|
2011-02-25 14:45:33 -08:00
|
|
|
case ir_txs:
|
2011-01-01 01:17:59 -08:00
|
|
|
tex->lod_info.lod = read_rvalue(s_lod);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (tex->lod_info.lod == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading LOD in (%s ...)",
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
tex->opcode_string());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2012-12-21 21:33:37 +13:00
|
|
|
case ir_txf_ms:
|
|
|
|
|
tex->lod_info.sample_index = read_rvalue(s_sample_index);
|
|
|
|
|
if (tex->lod_info.sample_index == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading sample_index in (txf_ms ...)");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
case ir_txd: {
|
|
|
|
|
s_expression *s_dx, *s_dy;
|
|
|
|
|
s_pattern dxdy_pat[] = { s_dx, s_dy };
|
|
|
|
|
if (!MATCH(s_lod, dxdy_pat)) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(s_lod, "expected (dPdx dPdy) in (txd ...)");
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
tex->lod_info.grad.dPdx = read_rvalue(s_dx);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (tex->lod_info.grad.dPdx == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading dPdx in (txd ...)");
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-01-01 01:17:59 -08:00
|
|
|
tex->lod_info.grad.dPdy = read_rvalue(s_dy);
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
if (tex->lod_info.grad.dPdy == NULL) {
|
2011-01-01 01:17:59 -08:00
|
|
|
ir_read_error(NULL, "when reading dPdy in (txd ...)");
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
return NULL;
|
2010-05-26 17:55:10 -07:00
|
|
|
}
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
break;
|
2010-05-26 17:55:10 -07:00
|
|
|
}
|
2013-10-05 18:26:56 +13:00
|
|
|
case ir_tg4:
|
|
|
|
|
tex->lod_info.component = read_rvalue(s_component);
|
|
|
|
|
if (tex->lod_info.component == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading component in (tg4 ...)");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
default:
|
2012-09-23 19:50:41 +10:00
|
|
|
// tex and lod don't have any extra parameters.
|
ir_reader: Add a pattern matching system and use it everywhere.
Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.
This was all very ad-hoc and a bit ugly. Error checking had to be done
at both steps 1, 3, and 4. Most code didn't even check the tag, relying
on the caller to do so. Not all callers did.
The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.
Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
2010-11-03 12:47:06 -07:00
|
|
|
break;
|
|
|
|
|
};
|
2010-05-26 17:55:10 -07:00
|
|
|
return tex;
|
|
|
|
|
}
|
2013-02-15 09:26:35 -06:00
|
|
|
|
|
|
|
|
ir_emit_vertex *
|
|
|
|
|
ir_reader::read_emit_vertex(s_expression *expr)
|
|
|
|
|
{
|
2014-06-08 13:16:26 +02:00
|
|
|
s_expression *s_stream = NULL;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "emit-vertex", s_stream };
|
2013-02-15 09:26:35 -06:00
|
|
|
|
|
|
|
|
if (MATCH(expr, pat)) {
|
2014-06-08 13:16:26 +02:00
|
|
|
ir_rvalue *stream = read_dereference(s_stream);
|
|
|
|
|
if (stream == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading stream info in emit-vertex");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return new(mem_ctx) ir_emit_vertex(stream);
|
2013-02-15 09:26:35 -06:00
|
|
|
}
|
|
|
|
|
ir_read_error(NULL, "when reading emit-vertex");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_end_primitive *
|
|
|
|
|
ir_reader::read_end_primitive(s_expression *expr)
|
|
|
|
|
{
|
2014-06-08 13:16:26 +02:00
|
|
|
s_expression *s_stream = NULL;
|
|
|
|
|
|
|
|
|
|
s_pattern pat[] = { "end-primitive", s_stream };
|
2013-02-15 09:26:35 -06:00
|
|
|
|
|
|
|
|
if (MATCH(expr, pat)) {
|
2014-06-08 13:16:26 +02:00
|
|
|
ir_rvalue *stream = read_dereference(s_stream);
|
|
|
|
|
if (stream == NULL) {
|
|
|
|
|
ir_read_error(NULL, "when reading stream info in end-primitive");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return new(mem_ctx) ir_end_primitive(stream);
|
2013-02-15 09:26:35 -06:00
|
|
|
}
|
|
|
|
|
ir_read_error(NULL, "when reading end-primitive");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-09-07 19:24:15 +12:00
|
|
|
|
|
|
|
|
ir_barrier *
|
|
|
|
|
ir_reader::read_barrier(s_expression *expr)
|
|
|
|
|
{
|
|
|
|
|
s_pattern pat[] = { "barrier" };
|
|
|
|
|
|
|
|
|
|
if (MATCH(expr, pat)) {
|
|
|
|
|
return new(mem_ctx) ir_barrier();
|
|
|
|
|
}
|
|
|
|
|
ir_read_error(NULL, "when reading barrier");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|