101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2010 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2101e04c3fSmrg * DEALINGS IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include "ir_reader.h"
2501e04c3fSmrg#include "glsl_parser_extras.h"
2601e04c3fSmrg#include "compiler/glsl_types.h"
2701e04c3fSmrg#include "s_expression.h"
2801e04c3fSmrg
2901e04c3fSmrgstatic const bool debug = false;
3001e04c3fSmrg
3101e04c3fSmrgnamespace {
3201e04c3fSmrg
3301e04c3fSmrgclass ir_reader {
3401e04c3fSmrgpublic:
3501e04c3fSmrg   ir_reader(_mesa_glsl_parse_state *);
3601e04c3fSmrg
3701e04c3fSmrg   void read(exec_list *instructions, const char *src, bool scan_for_protos);
3801e04c3fSmrg
3901e04c3fSmrgprivate:
4001e04c3fSmrg   void *mem_ctx;
4101e04c3fSmrg   _mesa_glsl_parse_state *state;
4201e04c3fSmrg
4301e04c3fSmrg   void ir_read_error(s_expression *, const char *fmt, ...);
4401e04c3fSmrg
4501e04c3fSmrg   const glsl_type *read_type(s_expression *);
4601e04c3fSmrg
4701e04c3fSmrg   void scan_for_prototypes(exec_list *, s_expression *);
4801e04c3fSmrg   ir_function *read_function(s_expression *, bool skip_body);
4901e04c3fSmrg   void read_function_sig(ir_function *, s_expression *, bool skip_body);
5001e04c3fSmrg
5101e04c3fSmrg   void read_instructions(exec_list *, s_expression *, ir_loop *);
5201e04c3fSmrg   ir_instruction *read_instruction(s_expression *, ir_loop *);
5301e04c3fSmrg   ir_variable *read_declaration(s_expression *);
5401e04c3fSmrg   ir_if *read_if(s_expression *, ir_loop *);
5501e04c3fSmrg   ir_loop *read_loop(s_expression *);
5601e04c3fSmrg   ir_call *read_call(s_expression *);
5701e04c3fSmrg   ir_return *read_return(s_expression *);
5801e04c3fSmrg   ir_rvalue *read_rvalue(s_expression *);
5901e04c3fSmrg   ir_assignment *read_assignment(s_expression *);
6001e04c3fSmrg   ir_expression *read_expression(s_expression *);
6101e04c3fSmrg   ir_swizzle *read_swizzle(s_expression *);
6201e04c3fSmrg   ir_constant *read_constant(s_expression *);
6301e04c3fSmrg   ir_texture *read_texture(s_expression *);
6401e04c3fSmrg   ir_emit_vertex *read_emit_vertex(s_expression *);
6501e04c3fSmrg   ir_end_primitive *read_end_primitive(s_expression *);
6601e04c3fSmrg   ir_barrier *read_barrier(s_expression *);
6701e04c3fSmrg
6801e04c3fSmrg   ir_dereference *read_dereference(s_expression *);
6901e04c3fSmrg   ir_dereference_variable *read_var_ref(s_expression *);
7001e04c3fSmrg};
7101e04c3fSmrg
7201e04c3fSmrg} /* anonymous namespace */
7301e04c3fSmrg
7401e04c3fSmrgir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state)
7501e04c3fSmrg{
7601e04c3fSmrg   this->mem_ctx = state;
7701e04c3fSmrg}
7801e04c3fSmrg
7901e04c3fSmrgvoid
8001e04c3fSmrg_mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions,
8101e04c3fSmrg		   const char *src, bool scan_for_protos)
8201e04c3fSmrg{
8301e04c3fSmrg   ir_reader r(state);
8401e04c3fSmrg   r.read(instructions, src, scan_for_protos);
8501e04c3fSmrg}
8601e04c3fSmrg
8701e04c3fSmrgvoid
8801e04c3fSmrgir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos)
8901e04c3fSmrg{
9001e04c3fSmrg   void *sx_mem_ctx = ralloc_context(NULL);
9101e04c3fSmrg   s_expression *expr = s_expression::read_expression(sx_mem_ctx, src);
9201e04c3fSmrg   if (expr == NULL) {
9301e04c3fSmrg      ir_read_error(NULL, "couldn't parse S-Expression.");
9401e04c3fSmrg      return;
9501e04c3fSmrg   }
9601e04c3fSmrg
9701e04c3fSmrg   if (scan_for_protos) {
9801e04c3fSmrg      scan_for_prototypes(instructions, expr);
9901e04c3fSmrg      if (state->error)
10001e04c3fSmrg	 return;
10101e04c3fSmrg   }
10201e04c3fSmrg
10301e04c3fSmrg   read_instructions(instructions, expr, NULL);
10401e04c3fSmrg   ralloc_free(sx_mem_ctx);
10501e04c3fSmrg
10601e04c3fSmrg   if (debug)
10701e04c3fSmrg      validate_ir_tree(instructions);
10801e04c3fSmrg}
10901e04c3fSmrg
11001e04c3fSmrgvoid
11101e04c3fSmrgir_reader::ir_read_error(s_expression *expr, const char *fmt, ...)
11201e04c3fSmrg{
11301e04c3fSmrg   va_list ap;
11401e04c3fSmrg
11501e04c3fSmrg   state->error = true;
11601e04c3fSmrg
11701e04c3fSmrg   if (state->current_function != NULL)
11801e04c3fSmrg      ralloc_asprintf_append(&state->info_log, "In function %s:\n",
11901e04c3fSmrg			     state->current_function->function_name());
12001e04c3fSmrg   ralloc_strcat(&state->info_log, "error: ");
12101e04c3fSmrg
12201e04c3fSmrg   va_start(ap, fmt);
12301e04c3fSmrg   ralloc_vasprintf_append(&state->info_log, fmt, ap);
12401e04c3fSmrg   va_end(ap);
12501e04c3fSmrg   ralloc_strcat(&state->info_log, "\n");
12601e04c3fSmrg
12701e04c3fSmrg   if (expr != NULL) {
12801e04c3fSmrg      ralloc_strcat(&state->info_log, "...in this context:\n   ");
12901e04c3fSmrg      expr->print();
13001e04c3fSmrg      ralloc_strcat(&state->info_log, "\n\n");
13101e04c3fSmrg   }
13201e04c3fSmrg}
13301e04c3fSmrg
13401e04c3fSmrgconst glsl_type *
13501e04c3fSmrgir_reader::read_type(s_expression *expr)
13601e04c3fSmrg{
13701e04c3fSmrg   s_expression *s_base_type;
13801e04c3fSmrg   s_int *s_size;
13901e04c3fSmrg
14001e04c3fSmrg   s_pattern pat[] = { "array", s_base_type, s_size };
14101e04c3fSmrg   if (MATCH(expr, pat)) {
14201e04c3fSmrg      const glsl_type *base_type = read_type(s_base_type);
14301e04c3fSmrg      if (base_type == NULL) {
14401e04c3fSmrg	 ir_read_error(NULL, "when reading base type of array type");
14501e04c3fSmrg	 return NULL;
14601e04c3fSmrg      }
14701e04c3fSmrg
14801e04c3fSmrg      return glsl_type::get_array_instance(base_type, s_size->value());
14901e04c3fSmrg   }
15001e04c3fSmrg
15101e04c3fSmrg   s_symbol *type_sym = SX_AS_SYMBOL(expr);
15201e04c3fSmrg   if (type_sym == NULL) {
15301e04c3fSmrg      ir_read_error(expr, "expected <type>");
15401e04c3fSmrg      return NULL;
15501e04c3fSmrg   }
15601e04c3fSmrg
15701e04c3fSmrg   const glsl_type *type = state->symbols->get_type(type_sym->value());
15801e04c3fSmrg   if (type == NULL)
15901e04c3fSmrg      ir_read_error(expr, "invalid type: %s", type_sym->value());
16001e04c3fSmrg
16101e04c3fSmrg   return type;
16201e04c3fSmrg}
16301e04c3fSmrg
16401e04c3fSmrg
16501e04c3fSmrgvoid
16601e04c3fSmrgir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr)
16701e04c3fSmrg{
16801e04c3fSmrg   s_list *list = SX_AS_LIST(expr);
16901e04c3fSmrg   if (list == NULL) {
17001e04c3fSmrg      ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
17101e04c3fSmrg      return;
17201e04c3fSmrg   }
17301e04c3fSmrg
17401e04c3fSmrg   foreach_in_list(s_list, sub, &list->subexpressions) {
17501e04c3fSmrg      if (!sub->is_list())
17601e04c3fSmrg	 continue; // not a (function ...); ignore it.
17701e04c3fSmrg
17801e04c3fSmrg      s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head());
17901e04c3fSmrg      if (tag == NULL || strcmp(tag->value(), "function") != 0)
18001e04c3fSmrg	 continue; // not a (function ...); ignore it.
18101e04c3fSmrg
18201e04c3fSmrg      ir_function *f = read_function(sub, true);
18301e04c3fSmrg      if (f == NULL)
18401e04c3fSmrg	 return;
18501e04c3fSmrg      instructions->push_tail(f);
18601e04c3fSmrg   }
18701e04c3fSmrg}
18801e04c3fSmrg
18901e04c3fSmrgir_function *
19001e04c3fSmrgir_reader::read_function(s_expression *expr, bool skip_body)
19101e04c3fSmrg{
19201e04c3fSmrg   bool added = false;
19301e04c3fSmrg   s_symbol *name;
19401e04c3fSmrg
19501e04c3fSmrg   s_pattern pat[] = { "function", name };
19601e04c3fSmrg   if (!PARTIAL_MATCH(expr, pat)) {
19701e04c3fSmrg      ir_read_error(expr, "Expected (function <name> (signature ...) ...)");
19801e04c3fSmrg      return NULL;
19901e04c3fSmrg   }
20001e04c3fSmrg
20101e04c3fSmrg   ir_function *f = state->symbols->get_function(name->value());
20201e04c3fSmrg   if (f == NULL) {
20301e04c3fSmrg      f = new(mem_ctx) ir_function(name->value());
20401e04c3fSmrg      added = state->symbols->add_function(f);
20501e04c3fSmrg      assert(added);
20601e04c3fSmrg   }
20701e04c3fSmrg
20801e04c3fSmrg   /* Skip over "function" tag and function name (which are guaranteed to be
20901e04c3fSmrg    * present by the above PARTIAL_MATCH call).
21001e04c3fSmrg    */
21101e04c3fSmrg   exec_node *node = ((s_list *) expr)->subexpressions.get_head_raw()->next->next;
21201e04c3fSmrg   for (/* nothing */; !node->is_tail_sentinel(); node = node->next) {
21301e04c3fSmrg      s_expression *s_sig = (s_expression *) node;
21401e04c3fSmrg      read_function_sig(f, s_sig, skip_body);
21501e04c3fSmrg   }
21601e04c3fSmrg   return added ? f : NULL;
21701e04c3fSmrg}
21801e04c3fSmrg
21901e04c3fSmrgstatic bool
22001e04c3fSmrgalways_available(const _mesa_glsl_parse_state *)
22101e04c3fSmrg{
22201e04c3fSmrg   return true;
22301e04c3fSmrg}
22401e04c3fSmrg
22501e04c3fSmrgvoid
22601e04c3fSmrgir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body)
22701e04c3fSmrg{
22801e04c3fSmrg   s_expression *type_expr;
22901e04c3fSmrg   s_list *paramlist;
23001e04c3fSmrg   s_list *body_list;
23101e04c3fSmrg
23201e04c3fSmrg   s_pattern pat[] = { "signature", type_expr, paramlist, body_list };
23301e04c3fSmrg   if (!MATCH(expr, pat)) {
23401e04c3fSmrg      ir_read_error(expr, "Expected (signature <type> (parameters ...) "
23501e04c3fSmrg			  "(<instruction> ...))");
23601e04c3fSmrg      return;
23701e04c3fSmrg   }
23801e04c3fSmrg
23901e04c3fSmrg   const glsl_type *return_type = read_type(type_expr);
24001e04c3fSmrg   if (return_type == NULL)
24101e04c3fSmrg      return;
24201e04c3fSmrg
24301e04c3fSmrg   s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head());
24401e04c3fSmrg   if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) {
24501e04c3fSmrg      ir_read_error(paramlist, "Expected (parameters ...)");
24601e04c3fSmrg      return;
24701e04c3fSmrg   }
24801e04c3fSmrg
24901e04c3fSmrg   // Read the parameters list into a temporary place.
25001e04c3fSmrg   exec_list hir_parameters;
25101e04c3fSmrg   state->symbols->push_scope();
25201e04c3fSmrg
25301e04c3fSmrg   /* Skip over the "parameters" tag. */
25401e04c3fSmrg   exec_node *node = paramlist->subexpressions.get_head_raw()->next;
25501e04c3fSmrg   for (/* nothing */; !node->is_tail_sentinel(); node = node->next) {
25601e04c3fSmrg      ir_variable *var = read_declaration((s_expression *) node);
25701e04c3fSmrg      if (var == NULL)
25801e04c3fSmrg	 return;
25901e04c3fSmrg
26001e04c3fSmrg      hir_parameters.push_tail(var);
26101e04c3fSmrg   }
26201e04c3fSmrg
26301e04c3fSmrg   ir_function_signature *sig =
26401e04c3fSmrg      f->exact_matching_signature(state, &hir_parameters);
26501e04c3fSmrg   if (sig == NULL && skip_body) {
26601e04c3fSmrg      /* If scanning for prototypes, generate a new signature. */
26701e04c3fSmrg      /* ir_reader doesn't know what languages support a given built-in, so
26801e04c3fSmrg       * just say that they're always available.  For now, other mechanisms
26901e04c3fSmrg       * guarantee the right built-ins are available.
27001e04c3fSmrg       */
27101e04c3fSmrg      sig = new(mem_ctx) ir_function_signature(return_type, always_available);
27201e04c3fSmrg      f->add_signature(sig);
27301e04c3fSmrg   } else if (sig != NULL) {
27401e04c3fSmrg      const char *badvar = sig->qualifiers_match(&hir_parameters);
27501e04c3fSmrg      if (badvar != NULL) {
27601e04c3fSmrg	 ir_read_error(expr, "function `%s' parameter `%s' qualifiers "
27701e04c3fSmrg		       "don't match prototype", f->name, badvar);
27801e04c3fSmrg	 return;
27901e04c3fSmrg      }
28001e04c3fSmrg
28101e04c3fSmrg      if (sig->return_type != return_type) {
28201e04c3fSmrg	 ir_read_error(expr, "function `%s' return type doesn't "
28301e04c3fSmrg		       "match prototype", f->name);
28401e04c3fSmrg	 return;
28501e04c3fSmrg      }
28601e04c3fSmrg   } else {
28701e04c3fSmrg      /* No prototype for this body exists - skip it. */
28801e04c3fSmrg      state->symbols->pop_scope();
28901e04c3fSmrg      return;
29001e04c3fSmrg   }
29101e04c3fSmrg   assert(sig != NULL);
29201e04c3fSmrg
29301e04c3fSmrg   sig->replace_parameters(&hir_parameters);
29401e04c3fSmrg
29501e04c3fSmrg   if (!skip_body && !body_list->subexpressions.is_empty()) {
29601e04c3fSmrg      if (sig->is_defined) {
29701e04c3fSmrg	 ir_read_error(expr, "function %s redefined", f->name);
29801e04c3fSmrg	 return;
29901e04c3fSmrg      }
30001e04c3fSmrg      state->current_function = sig;
30101e04c3fSmrg      read_instructions(&sig->body, body_list, NULL);
30201e04c3fSmrg      state->current_function = NULL;
30301e04c3fSmrg      sig->is_defined = true;
30401e04c3fSmrg   }
30501e04c3fSmrg
30601e04c3fSmrg   state->symbols->pop_scope();
30701e04c3fSmrg}
30801e04c3fSmrg
30901e04c3fSmrgvoid
31001e04c3fSmrgir_reader::read_instructions(exec_list *instructions, s_expression *expr,
31101e04c3fSmrg			     ir_loop *loop_ctx)
31201e04c3fSmrg{
31301e04c3fSmrg   // Read in a list of instructions
31401e04c3fSmrg   s_list *list = SX_AS_LIST(expr);
31501e04c3fSmrg   if (list == NULL) {
31601e04c3fSmrg      ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
31701e04c3fSmrg      return;
31801e04c3fSmrg   }
31901e04c3fSmrg
32001e04c3fSmrg   foreach_in_list(s_expression, sub, &list->subexpressions) {
32101e04c3fSmrg      ir_instruction *ir = read_instruction(sub, loop_ctx);
32201e04c3fSmrg      if (ir != NULL) {
32301e04c3fSmrg	 /* Global variable declarations should be moved to the top, before
32401e04c3fSmrg	  * any functions that might use them.  Functions are added to the
32501e04c3fSmrg	  * instruction stream when scanning for prototypes, so without this
32601e04c3fSmrg	  * hack, they always appear before variable declarations.
32701e04c3fSmrg	  */
32801e04c3fSmrg	 if (state->current_function == NULL && ir->as_variable() != NULL)
32901e04c3fSmrg	    instructions->push_head(ir);
33001e04c3fSmrg	 else
33101e04c3fSmrg	    instructions->push_tail(ir);
33201e04c3fSmrg      }
33301e04c3fSmrg   }
33401e04c3fSmrg}
33501e04c3fSmrg
33601e04c3fSmrg
33701e04c3fSmrgir_instruction *
33801e04c3fSmrgir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
33901e04c3fSmrg{
34001e04c3fSmrg   s_symbol *symbol = SX_AS_SYMBOL(expr);
34101e04c3fSmrg   if (symbol != NULL) {
34201e04c3fSmrg      if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL)
34301e04c3fSmrg	 return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break);
34401e04c3fSmrg      if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL)
34501e04c3fSmrg	 return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
34601e04c3fSmrg   }
34701e04c3fSmrg
34801e04c3fSmrg   s_list *list = SX_AS_LIST(expr);
34901e04c3fSmrg   if (list == NULL || list->subexpressions.is_empty()) {
35001e04c3fSmrg      ir_read_error(expr, "Invalid instruction.\n");
35101e04c3fSmrg      return NULL;
35201e04c3fSmrg   }
35301e04c3fSmrg
35401e04c3fSmrg   s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
35501e04c3fSmrg   if (tag == NULL) {
35601e04c3fSmrg      ir_read_error(expr, "expected instruction tag");
35701e04c3fSmrg      return NULL;
35801e04c3fSmrg   }
35901e04c3fSmrg
36001e04c3fSmrg   ir_instruction *inst = NULL;
36101e04c3fSmrg   if (strcmp(tag->value(), "declare") == 0) {
36201e04c3fSmrg      inst = read_declaration(list);
36301e04c3fSmrg   } else if (strcmp(tag->value(), "assign") == 0) {
36401e04c3fSmrg      inst = read_assignment(list);
36501e04c3fSmrg   } else if (strcmp(tag->value(), "if") == 0) {
36601e04c3fSmrg      inst = read_if(list, loop_ctx);
36701e04c3fSmrg   } else if (strcmp(tag->value(), "loop") == 0) {
36801e04c3fSmrg      inst = read_loop(list);
36901e04c3fSmrg   } else if (strcmp(tag->value(), "call") == 0) {
37001e04c3fSmrg      inst = read_call(list);
37101e04c3fSmrg   } else if (strcmp(tag->value(), "return") == 0) {
37201e04c3fSmrg      inst = read_return(list);
37301e04c3fSmrg   } else if (strcmp(tag->value(), "function") == 0) {
37401e04c3fSmrg      inst = read_function(list, false);
37501e04c3fSmrg   } else if (strcmp(tag->value(), "emit-vertex") == 0) {
37601e04c3fSmrg      inst = read_emit_vertex(list);
37701e04c3fSmrg   } else if (strcmp(tag->value(), "end-primitive") == 0) {
37801e04c3fSmrg      inst = read_end_primitive(list);
37901e04c3fSmrg   } else if (strcmp(tag->value(), "barrier") == 0) {
38001e04c3fSmrg      inst = read_barrier(list);
38101e04c3fSmrg   } else {
38201e04c3fSmrg      inst = read_rvalue(list);
38301e04c3fSmrg      if (inst == NULL)
38401e04c3fSmrg	 ir_read_error(NULL, "when reading instruction");
38501e04c3fSmrg   }
38601e04c3fSmrg   return inst;
38701e04c3fSmrg}
38801e04c3fSmrg
38901e04c3fSmrgir_variable *
39001e04c3fSmrgir_reader::read_declaration(s_expression *expr)
39101e04c3fSmrg{
39201e04c3fSmrg   s_list *s_quals;
39301e04c3fSmrg   s_expression *s_type;
39401e04c3fSmrg   s_symbol *s_name;
39501e04c3fSmrg
39601e04c3fSmrg   s_pattern pat[] = { "declare", s_quals, s_type, s_name };
39701e04c3fSmrg   if (!MATCH(expr, pat)) {
39801e04c3fSmrg      ir_read_error(expr, "expected (declare (<qualifiers>) <type> <name>)");
39901e04c3fSmrg      return NULL;
40001e04c3fSmrg   }
40101e04c3fSmrg
40201e04c3fSmrg   const glsl_type *type = read_type(s_type);
40301e04c3fSmrg   if (type == NULL)
40401e04c3fSmrg      return NULL;
40501e04c3fSmrg
40601e04c3fSmrg   ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(),
40701e04c3fSmrg					       ir_var_auto);
40801e04c3fSmrg
40901e04c3fSmrg   foreach_in_list(s_symbol, qualifier, &s_quals->subexpressions) {
41001e04c3fSmrg      if (!qualifier->is_symbol()) {
41101e04c3fSmrg	 ir_read_error(expr, "qualifier list must contain only symbols");
41201e04c3fSmrg	 return NULL;
41301e04c3fSmrg      }
41401e04c3fSmrg
41501e04c3fSmrg      // FINISHME: Check for duplicate/conflicting qualifiers.
41601e04c3fSmrg      if (strcmp(qualifier->value(), "centroid") == 0) {
41701e04c3fSmrg	 var->data.centroid = 1;
41801e04c3fSmrg      } else if (strcmp(qualifier->value(), "sample") == 0) {
41901e04c3fSmrg         var->data.sample = 1;
42001e04c3fSmrg      } else if (strcmp(qualifier->value(), "patch") == 0) {
42101e04c3fSmrg         var->data.patch = 1;
422993e1d59Smrg      } else if (strcmp(qualifier->value(), "explicit_invariant") == 0) {
423993e1d59Smrg         var->data.explicit_invariant = true;
42401e04c3fSmrg      } else if (strcmp(qualifier->value(), "invariant") == 0) {
425993e1d59Smrg         var->data.invariant = true;
42601e04c3fSmrg      } else if (strcmp(qualifier->value(), "uniform") == 0) {
42701e04c3fSmrg	 var->data.mode = ir_var_uniform;
42801e04c3fSmrg      } else if (strcmp(qualifier->value(), "shader_storage") == 0) {
42901e04c3fSmrg	 var->data.mode = ir_var_shader_storage;
43001e04c3fSmrg      } else if (strcmp(qualifier->value(), "auto") == 0) {
43101e04c3fSmrg	 var->data.mode = ir_var_auto;
43201e04c3fSmrg      } else if (strcmp(qualifier->value(), "in") == 0) {
43301e04c3fSmrg	 var->data.mode = ir_var_function_in;
43401e04c3fSmrg      } else if (strcmp(qualifier->value(), "shader_in") == 0) {
43501e04c3fSmrg         var->data.mode = ir_var_shader_in;
43601e04c3fSmrg      } else if (strcmp(qualifier->value(), "const_in") == 0) {
43701e04c3fSmrg	 var->data.mode = ir_var_const_in;
43801e04c3fSmrg      } else if (strcmp(qualifier->value(), "out") == 0) {
43901e04c3fSmrg	 var->data.mode = ir_var_function_out;
44001e04c3fSmrg      } else if (strcmp(qualifier->value(), "shader_out") == 0) {
44101e04c3fSmrg	 var->data.mode = ir_var_shader_out;
44201e04c3fSmrg      } else if (strcmp(qualifier->value(), "inout") == 0) {
44301e04c3fSmrg	 var->data.mode = ir_var_function_inout;
44401e04c3fSmrg      } else if (strcmp(qualifier->value(), "temporary") == 0) {
44501e04c3fSmrg	 var->data.mode = ir_var_temporary;
44601e04c3fSmrg      } else if (strcmp(qualifier->value(), "stream1") == 0) {
44701e04c3fSmrg	 var->data.stream = 1;
44801e04c3fSmrg      } else if (strcmp(qualifier->value(), "stream2") == 0) {
44901e04c3fSmrg	 var->data.stream = 2;
45001e04c3fSmrg      } else if (strcmp(qualifier->value(), "stream3") == 0) {
45101e04c3fSmrg	 var->data.stream = 3;
45201e04c3fSmrg      } else if (strcmp(qualifier->value(), "smooth") == 0) {
45301e04c3fSmrg	 var->data.interpolation = INTERP_MODE_SMOOTH;
45401e04c3fSmrg      } else if (strcmp(qualifier->value(), "flat") == 0) {
45501e04c3fSmrg	 var->data.interpolation = INTERP_MODE_FLAT;
45601e04c3fSmrg      } else if (strcmp(qualifier->value(), "noperspective") == 0) {
45701e04c3fSmrg	 var->data.interpolation = INTERP_MODE_NOPERSPECTIVE;
45801e04c3fSmrg      } else {
45901e04c3fSmrg	 ir_read_error(expr, "unknown qualifier: %s", qualifier->value());
46001e04c3fSmrg	 return NULL;
46101e04c3fSmrg      }
46201e04c3fSmrg   }
46301e04c3fSmrg
46401e04c3fSmrg   // Add the variable to the symbol table
46501e04c3fSmrg   state->symbols->add_variable(var);
46601e04c3fSmrg
46701e04c3fSmrg   return var;
46801e04c3fSmrg}
46901e04c3fSmrg
47001e04c3fSmrg
47101e04c3fSmrgir_if *
47201e04c3fSmrgir_reader::read_if(s_expression *expr, ir_loop *loop_ctx)
47301e04c3fSmrg{
47401e04c3fSmrg   s_expression *s_cond;
47501e04c3fSmrg   s_expression *s_then;
47601e04c3fSmrg   s_expression *s_else;
47701e04c3fSmrg
47801e04c3fSmrg   s_pattern pat[] = { "if", s_cond, s_then, s_else };
47901e04c3fSmrg   if (!MATCH(expr, pat)) {
48001e04c3fSmrg      ir_read_error(expr, "expected (if <condition> (<then>...) (<else>...))");
48101e04c3fSmrg      return NULL;
48201e04c3fSmrg   }
48301e04c3fSmrg
48401e04c3fSmrg   ir_rvalue *condition = read_rvalue(s_cond);
48501e04c3fSmrg   if (condition == NULL) {
48601e04c3fSmrg      ir_read_error(NULL, "when reading condition of (if ...)");
48701e04c3fSmrg      return NULL;
48801e04c3fSmrg   }
48901e04c3fSmrg
49001e04c3fSmrg   ir_if *iff = new(mem_ctx) ir_if(condition);
49101e04c3fSmrg
49201e04c3fSmrg   read_instructions(&iff->then_instructions, s_then, loop_ctx);
49301e04c3fSmrg   read_instructions(&iff->else_instructions, s_else, loop_ctx);
49401e04c3fSmrg   if (state->error) {
49501e04c3fSmrg      delete iff;
49601e04c3fSmrg      iff = NULL;
49701e04c3fSmrg   }
49801e04c3fSmrg   return iff;
49901e04c3fSmrg}
50001e04c3fSmrg
50101e04c3fSmrg
50201e04c3fSmrgir_loop *
50301e04c3fSmrgir_reader::read_loop(s_expression *expr)
50401e04c3fSmrg{
50501e04c3fSmrg   s_expression *s_body;
50601e04c3fSmrg
50701e04c3fSmrg   s_pattern loop_pat[] = { "loop", s_body };
50801e04c3fSmrg   if (!MATCH(expr, loop_pat)) {
50901e04c3fSmrg      ir_read_error(expr, "expected (loop <body>)");
51001e04c3fSmrg      return NULL;
51101e04c3fSmrg   }
51201e04c3fSmrg
51301e04c3fSmrg   ir_loop *loop = new(mem_ctx) ir_loop;
51401e04c3fSmrg
51501e04c3fSmrg   read_instructions(&loop->body_instructions, s_body, loop);
51601e04c3fSmrg   if (state->error) {
51701e04c3fSmrg      delete loop;
51801e04c3fSmrg      loop = NULL;
51901e04c3fSmrg   }
52001e04c3fSmrg   return loop;
52101e04c3fSmrg}
52201e04c3fSmrg
52301e04c3fSmrg
52401e04c3fSmrgir_return *
52501e04c3fSmrgir_reader::read_return(s_expression *expr)
52601e04c3fSmrg{
52701e04c3fSmrg   s_expression *s_retval;
52801e04c3fSmrg
52901e04c3fSmrg   s_pattern return_value_pat[] = { "return", s_retval};
53001e04c3fSmrg   s_pattern return_void_pat[] = { "return" };
53101e04c3fSmrg   if (MATCH(expr, return_value_pat)) {
53201e04c3fSmrg      ir_rvalue *retval = read_rvalue(s_retval);
53301e04c3fSmrg      if (retval == NULL) {
53401e04c3fSmrg         ir_read_error(NULL, "when reading return value");
53501e04c3fSmrg         return NULL;
53601e04c3fSmrg      }
53701e04c3fSmrg      return new(mem_ctx) ir_return(retval);
53801e04c3fSmrg   } else if (MATCH(expr, return_void_pat)) {
53901e04c3fSmrg      return new(mem_ctx) ir_return;
54001e04c3fSmrg   } else {
54101e04c3fSmrg      ir_read_error(expr, "expected (return <rvalue>) or (return)");
54201e04c3fSmrg      return NULL;
54301e04c3fSmrg   }
54401e04c3fSmrg}
54501e04c3fSmrg
54601e04c3fSmrg
54701e04c3fSmrgir_rvalue *
54801e04c3fSmrgir_reader::read_rvalue(s_expression *expr)
54901e04c3fSmrg{
55001e04c3fSmrg   s_list *list = SX_AS_LIST(expr);
55101e04c3fSmrg   if (list == NULL || list->subexpressions.is_empty())
55201e04c3fSmrg      return NULL;
55301e04c3fSmrg
55401e04c3fSmrg   s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
55501e04c3fSmrg   if (tag == NULL) {
55601e04c3fSmrg      ir_read_error(expr, "expected rvalue tag");
55701e04c3fSmrg      return NULL;
55801e04c3fSmrg   }
55901e04c3fSmrg
56001e04c3fSmrg   ir_rvalue *rvalue = read_dereference(list);
56101e04c3fSmrg   if (rvalue != NULL || state->error)
56201e04c3fSmrg      return rvalue;
56301e04c3fSmrg   else if (strcmp(tag->value(), "swiz") == 0) {
56401e04c3fSmrg      rvalue = read_swizzle(list);
56501e04c3fSmrg   } else if (strcmp(tag->value(), "expression") == 0) {
56601e04c3fSmrg      rvalue = read_expression(list);
56701e04c3fSmrg   } else if (strcmp(tag->value(), "constant") == 0) {
56801e04c3fSmrg      rvalue = read_constant(list);
56901e04c3fSmrg   } else {
57001e04c3fSmrg      rvalue = read_texture(list);
57101e04c3fSmrg      if (rvalue == NULL && !state->error)
57201e04c3fSmrg	 ir_read_error(expr, "unrecognized rvalue tag: %s", tag->value());
57301e04c3fSmrg   }
57401e04c3fSmrg
57501e04c3fSmrg   return rvalue;
57601e04c3fSmrg}
57701e04c3fSmrg
57801e04c3fSmrgir_assignment *
57901e04c3fSmrgir_reader::read_assignment(s_expression *expr)
58001e04c3fSmrg{
58101e04c3fSmrg   s_expression *cond_expr = NULL;
58201e04c3fSmrg   s_expression *lhs_expr, *rhs_expr;
58301e04c3fSmrg   s_list       *mask_list;
58401e04c3fSmrg
58501e04c3fSmrg   s_pattern pat4[] = { "assign",            mask_list, lhs_expr, rhs_expr };
58601e04c3fSmrg   s_pattern pat5[] = { "assign", cond_expr, mask_list, lhs_expr, rhs_expr };
58701e04c3fSmrg   if (!MATCH(expr, pat4) && !MATCH(expr, pat5)) {
58801e04c3fSmrg      ir_read_error(expr, "expected (assign [<condition>] (<write mask>) "
58901e04c3fSmrg			  "<lhs> <rhs>)");
59001e04c3fSmrg      return NULL;
59101e04c3fSmrg   }
59201e04c3fSmrg
59301e04c3fSmrg   ir_rvalue *condition = NULL;
59401e04c3fSmrg   if (cond_expr != NULL) {
59501e04c3fSmrg      condition = read_rvalue(cond_expr);
59601e04c3fSmrg      if (condition == NULL) {
59701e04c3fSmrg	 ir_read_error(NULL, "when reading condition of assignment");
59801e04c3fSmrg	 return NULL;
59901e04c3fSmrg      }
60001e04c3fSmrg   }
60101e04c3fSmrg
60201e04c3fSmrg   unsigned mask = 0;
60301e04c3fSmrg
60401e04c3fSmrg   s_symbol *mask_symbol;
60501e04c3fSmrg   s_pattern mask_pat[] = { mask_symbol };
60601e04c3fSmrg   if (MATCH(mask_list, mask_pat)) {
60701e04c3fSmrg      const char *mask_str = mask_symbol->value();
60801e04c3fSmrg      unsigned mask_length = strlen(mask_str);
60901e04c3fSmrg      if (mask_length > 4) {
61001e04c3fSmrg	 ir_read_error(expr, "invalid write mask: %s", mask_str);
61101e04c3fSmrg	 return NULL;
61201e04c3fSmrg      }
61301e04c3fSmrg
61401e04c3fSmrg      const unsigned idx_map[] = { 3, 0, 1, 2 }; /* w=bit 3, x=0, y=1, z=2 */
61501e04c3fSmrg
61601e04c3fSmrg      for (unsigned i = 0; i < mask_length; i++) {
61701e04c3fSmrg	 if (mask_str[i] < 'w' || mask_str[i] > 'z') {
61801e04c3fSmrg	    ir_read_error(expr, "write mask contains invalid character: %c",
61901e04c3fSmrg			  mask_str[i]);
62001e04c3fSmrg	    return NULL;
62101e04c3fSmrg	 }
62201e04c3fSmrg	 mask |= 1 << idx_map[mask_str[i] - 'w'];
62301e04c3fSmrg      }
62401e04c3fSmrg   } else if (!mask_list->subexpressions.is_empty()) {
62501e04c3fSmrg      ir_read_error(mask_list, "expected () or (<write mask>)");
62601e04c3fSmrg      return NULL;
62701e04c3fSmrg   }
62801e04c3fSmrg
62901e04c3fSmrg   ir_dereference *lhs = read_dereference(lhs_expr);
63001e04c3fSmrg   if (lhs == NULL) {
63101e04c3fSmrg      ir_read_error(NULL, "when reading left-hand side of assignment");
63201e04c3fSmrg      return NULL;
63301e04c3fSmrg   }
63401e04c3fSmrg
63501e04c3fSmrg   ir_rvalue *rhs = read_rvalue(rhs_expr);
63601e04c3fSmrg   if (rhs == NULL) {
63701e04c3fSmrg      ir_read_error(NULL, "when reading right-hand side of assignment");
63801e04c3fSmrg      return NULL;
63901e04c3fSmrg   }
64001e04c3fSmrg
64101e04c3fSmrg   if (mask == 0 && (lhs->type->is_vector() || lhs->type->is_scalar())) {
64201e04c3fSmrg      ir_read_error(expr, "non-zero write mask required.");
64301e04c3fSmrg      return NULL;
64401e04c3fSmrg   }
64501e04c3fSmrg
64601e04c3fSmrg   return new(mem_ctx) ir_assignment(lhs, rhs, condition, mask);
64701e04c3fSmrg}
64801e04c3fSmrg
64901e04c3fSmrgir_call *
65001e04c3fSmrgir_reader::read_call(s_expression *expr)
65101e04c3fSmrg{
65201e04c3fSmrg   s_symbol *name;
65301e04c3fSmrg   s_list *params;
65401e04c3fSmrg   s_list *s_return = NULL;
65501e04c3fSmrg
65601e04c3fSmrg   ir_dereference_variable *return_deref = NULL;
65701e04c3fSmrg
65801e04c3fSmrg   s_pattern void_pat[] = { "call", name, params };
65901e04c3fSmrg   s_pattern non_void_pat[] = { "call", name, s_return, params };
66001e04c3fSmrg   if (MATCH(expr, non_void_pat)) {
66101e04c3fSmrg      return_deref = read_var_ref(s_return);
66201e04c3fSmrg      if (return_deref == NULL) {
66301e04c3fSmrg	 ir_read_error(s_return, "when reading a call's return storage");
66401e04c3fSmrg	 return NULL;
66501e04c3fSmrg      }
66601e04c3fSmrg   } else if (!MATCH(expr, void_pat)) {
66701e04c3fSmrg      ir_read_error(expr, "expected (call <name> [<deref>] (<param> ...))");
66801e04c3fSmrg      return NULL;
66901e04c3fSmrg   }
67001e04c3fSmrg
67101e04c3fSmrg   exec_list parameters;
67201e04c3fSmrg
67301e04c3fSmrg   foreach_in_list(s_expression, e, &params->subexpressions) {
67401e04c3fSmrg      ir_rvalue *param = read_rvalue(e);
67501e04c3fSmrg      if (param == NULL) {
67601e04c3fSmrg	 ir_read_error(e, "when reading parameter to function call");
67701e04c3fSmrg	 return NULL;
67801e04c3fSmrg      }
67901e04c3fSmrg      parameters.push_tail(param);
68001e04c3fSmrg   }
68101e04c3fSmrg
68201e04c3fSmrg   ir_function *f = state->symbols->get_function(name->value());
68301e04c3fSmrg   if (f == NULL) {
68401e04c3fSmrg      ir_read_error(expr, "found call to undefined function %s",
68501e04c3fSmrg		    name->value());
68601e04c3fSmrg      return NULL;
68701e04c3fSmrg   }
68801e04c3fSmrg
68901e04c3fSmrg   ir_function_signature *callee =
69001e04c3fSmrg      f->matching_signature(state, &parameters, true);
69101e04c3fSmrg   if (callee == NULL) {
69201e04c3fSmrg      ir_read_error(expr, "couldn't find matching signature for function "
69301e04c3fSmrg                    "%s", name->value());
69401e04c3fSmrg      return NULL;
69501e04c3fSmrg   }
69601e04c3fSmrg
69701e04c3fSmrg   if (callee->return_type == glsl_type::void_type && return_deref) {
69801e04c3fSmrg      ir_read_error(expr, "call has return value storage but void type");
69901e04c3fSmrg      return NULL;
70001e04c3fSmrg   } else if (callee->return_type != glsl_type::void_type && !return_deref) {
70101e04c3fSmrg      ir_read_error(expr, "call has non-void type but no return value storage");
70201e04c3fSmrg      return NULL;
70301e04c3fSmrg   }
70401e04c3fSmrg
70501e04c3fSmrg   return new(mem_ctx) ir_call(callee, return_deref, &parameters);
70601e04c3fSmrg}
70701e04c3fSmrg
70801e04c3fSmrgir_expression *
70901e04c3fSmrgir_reader::read_expression(s_expression *expr)
71001e04c3fSmrg{
71101e04c3fSmrg   s_expression *s_type;
71201e04c3fSmrg   s_symbol *s_op;
71301e04c3fSmrg   s_expression *s_arg[4] = {NULL};
71401e04c3fSmrg
71501e04c3fSmrg   s_pattern pat[] = { "expression", s_type, s_op, s_arg[0] };
71601e04c3fSmrg   if (!PARTIAL_MATCH(expr, pat)) {
71701e04c3fSmrg      ir_read_error(expr, "expected (expression <type> <operator> "
71801e04c3fSmrg			  "<operand> [<operand>] [<operand>] [<operand>])");
71901e04c3fSmrg      return NULL;
72001e04c3fSmrg   }
72101e04c3fSmrg   s_arg[1] = (s_expression *) s_arg[0]->next; // may be tail sentinel
72201e04c3fSmrg   s_arg[2] = (s_expression *) s_arg[1]->next; // may be tail sentinel or NULL
72301e04c3fSmrg   if (s_arg[2])
72401e04c3fSmrg      s_arg[3] = (s_expression *) s_arg[2]->next; // may be tail sentinel or NULL
72501e04c3fSmrg
72601e04c3fSmrg   const glsl_type *type = read_type(s_type);
72701e04c3fSmrg   if (type == NULL)
72801e04c3fSmrg      return NULL;
72901e04c3fSmrg
73001e04c3fSmrg   /* Read the operator */
73101e04c3fSmrg   ir_expression_operation op = ir_expression::get_operator(s_op->value());
73201e04c3fSmrg   if (op == (ir_expression_operation) -1) {
73301e04c3fSmrg      ir_read_error(expr, "invalid operator: %s", s_op->value());
73401e04c3fSmrg      return NULL;
73501e04c3fSmrg   }
73601e04c3fSmrg
73701e04c3fSmrg   /* Skip "expression" <type> <operation> by subtracting 3. */
73801e04c3fSmrg   int num_operands = (int) ((s_list *) expr)->subexpressions.length() - 3;
73901e04c3fSmrg
74001e04c3fSmrg   int expected_operands = ir_expression::get_num_operands(op);
74101e04c3fSmrg   if (num_operands != expected_operands) {
74201e04c3fSmrg      ir_read_error(expr, "found %d expression operands, expected %d",
74301e04c3fSmrg                    num_operands, expected_operands);
74401e04c3fSmrg      return NULL;
74501e04c3fSmrg   }
74601e04c3fSmrg
74701e04c3fSmrg   ir_rvalue *arg[4] = {NULL};
74801e04c3fSmrg   for (int i = 0; i < num_operands; i++) {
74901e04c3fSmrg      arg[i] = read_rvalue(s_arg[i]);
75001e04c3fSmrg      if (arg[i] == NULL) {
75101e04c3fSmrg         ir_read_error(NULL, "when reading operand #%d of %s", i, s_op->value());
75201e04c3fSmrg         return NULL;
75301e04c3fSmrg      }
75401e04c3fSmrg   }
75501e04c3fSmrg
75601e04c3fSmrg   return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2], arg[3]);
75701e04c3fSmrg}
75801e04c3fSmrg
75901e04c3fSmrgir_swizzle *
76001e04c3fSmrgir_reader::read_swizzle(s_expression *expr)
76101e04c3fSmrg{
76201e04c3fSmrg   s_symbol *swiz;
76301e04c3fSmrg   s_expression *sub;
76401e04c3fSmrg
76501e04c3fSmrg   s_pattern pat[] = { "swiz", swiz, sub };
76601e04c3fSmrg   if (!MATCH(expr, pat)) {
76701e04c3fSmrg      ir_read_error(expr, "expected (swiz <swizzle> <rvalue>)");
76801e04c3fSmrg      return NULL;
76901e04c3fSmrg   }
77001e04c3fSmrg
77101e04c3fSmrg   if (strlen(swiz->value()) > 4) {
77201e04c3fSmrg      ir_read_error(expr, "expected a valid swizzle; found %s", swiz->value());
77301e04c3fSmrg      return NULL;
77401e04c3fSmrg   }
77501e04c3fSmrg
77601e04c3fSmrg   ir_rvalue *rvalue = read_rvalue(sub);
77701e04c3fSmrg   if (rvalue == NULL)
77801e04c3fSmrg      return NULL;
77901e04c3fSmrg
78001e04c3fSmrg   ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(),
78101e04c3fSmrg				       rvalue->type->vector_elements);
78201e04c3fSmrg   if (ir == NULL)
78301e04c3fSmrg      ir_read_error(expr, "invalid swizzle");
78401e04c3fSmrg
78501e04c3fSmrg   return ir;
78601e04c3fSmrg}
78701e04c3fSmrg
78801e04c3fSmrgir_constant *
78901e04c3fSmrgir_reader::read_constant(s_expression *expr)
79001e04c3fSmrg{
79101e04c3fSmrg   s_expression *type_expr;
79201e04c3fSmrg   s_list *values;
79301e04c3fSmrg
79401e04c3fSmrg   s_pattern pat[] = { "constant", type_expr, values };
79501e04c3fSmrg   if (!MATCH(expr, pat)) {
79601e04c3fSmrg      ir_read_error(expr, "expected (constant <type> (...))");
79701e04c3fSmrg      return NULL;
79801e04c3fSmrg   }
79901e04c3fSmrg
80001e04c3fSmrg   const glsl_type *type = read_type(type_expr);
80101e04c3fSmrg   if (type == NULL)
80201e04c3fSmrg      return NULL;
80301e04c3fSmrg
80401e04c3fSmrg   if (values == NULL) {
80501e04c3fSmrg      ir_read_error(expr, "expected (constant <type> (...))");
80601e04c3fSmrg      return NULL;
80701e04c3fSmrg   }
80801e04c3fSmrg
80901e04c3fSmrg   if (type->is_array()) {
81001e04c3fSmrg      unsigned elements_supplied = 0;
81101e04c3fSmrg      exec_list elements;
81201e04c3fSmrg      foreach_in_list(s_expression, elt, &values->subexpressions) {
81301e04c3fSmrg	 ir_constant *ir_elt = read_constant(elt);
81401e04c3fSmrg	 if (ir_elt == NULL)
81501e04c3fSmrg	    return NULL;
81601e04c3fSmrg	 elements.push_tail(ir_elt);
81701e04c3fSmrg	 elements_supplied++;
81801e04c3fSmrg      }
81901e04c3fSmrg
82001e04c3fSmrg      if (elements_supplied != type->length) {
82101e04c3fSmrg	 ir_read_error(values, "expected exactly %u array elements, "
82201e04c3fSmrg		       "given %u", type->length, elements_supplied);
82301e04c3fSmrg	 return NULL;
82401e04c3fSmrg      }
82501e04c3fSmrg      return new(mem_ctx) ir_constant(type, &elements);
82601e04c3fSmrg   }
82701e04c3fSmrg
82801e04c3fSmrg   ir_constant_data data = { { 0 } };
82901e04c3fSmrg
83001e04c3fSmrg   // Read in list of values (at most 16).
83101e04c3fSmrg   unsigned k = 0;
83201e04c3fSmrg   foreach_in_list(s_expression, expr, &values->subexpressions) {
83301e04c3fSmrg      if (k >= 16) {
83401e04c3fSmrg	 ir_read_error(values, "expected at most 16 numbers");
83501e04c3fSmrg	 return NULL;
83601e04c3fSmrg      }
83701e04c3fSmrg
83801e04c3fSmrg      if (type->is_float()) {
83901e04c3fSmrg	 s_number *value = SX_AS_NUMBER(expr);
84001e04c3fSmrg	 if (value == NULL) {
84101e04c3fSmrg	    ir_read_error(values, "expected numbers");
84201e04c3fSmrg	    return NULL;
84301e04c3fSmrg	 }
84401e04c3fSmrg	 data.f[k] = value->fvalue();
84501e04c3fSmrg      } else {
84601e04c3fSmrg	 s_int *value = SX_AS_INT(expr);
84701e04c3fSmrg	 if (value == NULL) {
84801e04c3fSmrg	    ir_read_error(values, "expected integers");
84901e04c3fSmrg	    return NULL;
85001e04c3fSmrg	 }
85101e04c3fSmrg
85201e04c3fSmrg	 switch (type->base_type) {
85301e04c3fSmrg	 case GLSL_TYPE_UINT: {
85401e04c3fSmrg	    data.u[k] = value->value();
85501e04c3fSmrg	    break;
85601e04c3fSmrg	 }
85701e04c3fSmrg	 case GLSL_TYPE_INT: {
85801e04c3fSmrg	    data.i[k] = value->value();
85901e04c3fSmrg	    break;
86001e04c3fSmrg	 }
86101e04c3fSmrg	 case GLSL_TYPE_BOOL: {
86201e04c3fSmrg	    data.b[k] = value->value();
86301e04c3fSmrg	    break;
86401e04c3fSmrg	 }
86501e04c3fSmrg	 default:
86601e04c3fSmrg	    ir_read_error(values, "unsupported constant type");
86701e04c3fSmrg	    return NULL;
86801e04c3fSmrg	 }
86901e04c3fSmrg      }
87001e04c3fSmrg      ++k;
87101e04c3fSmrg   }
87201e04c3fSmrg   if (k != type->components()) {
87301e04c3fSmrg      ir_read_error(values, "expected %u constant values, found %u",
87401e04c3fSmrg		    type->components(), k);
87501e04c3fSmrg      return NULL;
87601e04c3fSmrg   }
87701e04c3fSmrg
87801e04c3fSmrg   return new(mem_ctx) ir_constant(type, &data);
87901e04c3fSmrg}
88001e04c3fSmrg
88101e04c3fSmrgir_dereference_variable *
88201e04c3fSmrgir_reader::read_var_ref(s_expression *expr)
88301e04c3fSmrg{
88401e04c3fSmrg   s_symbol *s_var;
88501e04c3fSmrg   s_pattern var_pat[] = { "var_ref", s_var };
88601e04c3fSmrg
88701e04c3fSmrg   if (MATCH(expr, var_pat)) {
88801e04c3fSmrg      ir_variable *var = state->symbols->get_variable(s_var->value());
88901e04c3fSmrg      if (var == NULL) {
89001e04c3fSmrg	 ir_read_error(expr, "undeclared variable: %s", s_var->value());
89101e04c3fSmrg	 return NULL;
89201e04c3fSmrg      }
89301e04c3fSmrg      return new(mem_ctx) ir_dereference_variable(var);
89401e04c3fSmrg   }
89501e04c3fSmrg   return NULL;
89601e04c3fSmrg}
89701e04c3fSmrg
89801e04c3fSmrgir_dereference *
89901e04c3fSmrgir_reader::read_dereference(s_expression *expr)
90001e04c3fSmrg{
90101e04c3fSmrg   s_expression *s_subject;
90201e04c3fSmrg   s_expression *s_index;
90301e04c3fSmrg   s_symbol *s_field;
90401e04c3fSmrg
90501e04c3fSmrg   s_pattern array_pat[] = { "array_ref", s_subject, s_index };
90601e04c3fSmrg   s_pattern record_pat[] = { "record_ref", s_subject, s_field };
90701e04c3fSmrg
90801e04c3fSmrg   ir_dereference_variable *var_ref = read_var_ref(expr);
90901e04c3fSmrg   if (var_ref != NULL) {
91001e04c3fSmrg      return var_ref;
91101e04c3fSmrg   } else if (MATCH(expr, array_pat)) {
91201e04c3fSmrg      ir_rvalue *subject = read_rvalue(s_subject);
91301e04c3fSmrg      if (subject == NULL) {
91401e04c3fSmrg	 ir_read_error(NULL, "when reading the subject of an array_ref");
91501e04c3fSmrg	 return NULL;
91601e04c3fSmrg      }
91701e04c3fSmrg
91801e04c3fSmrg      ir_rvalue *idx = read_rvalue(s_index);
91901e04c3fSmrg      if (idx == NULL) {
92001e04c3fSmrg	 ir_read_error(NULL, "when reading the index of an array_ref");
92101e04c3fSmrg	 return NULL;
92201e04c3fSmrg      }
92301e04c3fSmrg      return new(mem_ctx) ir_dereference_array(subject, idx);
92401e04c3fSmrg   } else if (MATCH(expr, record_pat)) {
92501e04c3fSmrg      ir_rvalue *subject = read_rvalue(s_subject);
92601e04c3fSmrg      if (subject == NULL) {
92701e04c3fSmrg	 ir_read_error(NULL, "when reading the subject of a record_ref");
92801e04c3fSmrg	 return NULL;
92901e04c3fSmrg      }
93001e04c3fSmrg      return new(mem_ctx) ir_dereference_record(subject, s_field->value());
93101e04c3fSmrg   }
93201e04c3fSmrg   return NULL;
93301e04c3fSmrg}
93401e04c3fSmrg
93501e04c3fSmrgir_texture *
93601e04c3fSmrgir_reader::read_texture(s_expression *expr)
93701e04c3fSmrg{
93801e04c3fSmrg   s_symbol *tag = NULL;
93901e04c3fSmrg   s_expression *s_type = NULL;
94001e04c3fSmrg   s_expression *s_sampler = NULL;
94101e04c3fSmrg   s_expression *s_coord = NULL;
94201e04c3fSmrg   s_expression *s_offset = NULL;
94301e04c3fSmrg   s_expression *s_proj = NULL;
94401e04c3fSmrg   s_list *s_shadow = NULL;
94501e04c3fSmrg   s_expression *s_lod = NULL;
94601e04c3fSmrg   s_expression *s_sample_index = NULL;
94701e04c3fSmrg   s_expression *s_component = NULL;
94801e04c3fSmrg
94901e04c3fSmrg   ir_texture_opcode op = ir_tex; /* silence warning */
95001e04c3fSmrg
95101e04c3fSmrg   s_pattern tex_pattern[] =
95201e04c3fSmrg      { "tex", s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow };
95301e04c3fSmrg   s_pattern lod_pattern[] =
95401e04c3fSmrg      { "lod", s_type, s_sampler, s_coord };
95501e04c3fSmrg   s_pattern txf_pattern[] =
95601e04c3fSmrg      { "txf", s_type, s_sampler, s_coord, s_offset, s_lod };
95701e04c3fSmrg   s_pattern txf_ms_pattern[] =
95801e04c3fSmrg      { "txf_ms", s_type, s_sampler, s_coord, s_sample_index };
95901e04c3fSmrg   s_pattern txs_pattern[] =
96001e04c3fSmrg      { "txs", s_type, s_sampler, s_lod };
96101e04c3fSmrg   s_pattern tg4_pattern[] =
96201e04c3fSmrg      { "tg4", s_type, s_sampler, s_coord, s_offset, s_component };
96301e04c3fSmrg   s_pattern query_levels_pattern[] =
96401e04c3fSmrg      { "query_levels", s_type, s_sampler };
96501e04c3fSmrg   s_pattern texture_samples_pattern[] =
96601e04c3fSmrg      { "samples", s_type, s_sampler };
96701e04c3fSmrg   s_pattern other_pattern[] =
96801e04c3fSmrg      { tag, s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod };
96901e04c3fSmrg
97001e04c3fSmrg   if (MATCH(expr, lod_pattern)) {
97101e04c3fSmrg      op = ir_lod;
97201e04c3fSmrg   } else if (MATCH(expr, tex_pattern)) {
97301e04c3fSmrg      op = ir_tex;
97401e04c3fSmrg   } else if (MATCH(expr, txf_pattern)) {
97501e04c3fSmrg      op = ir_txf;
97601e04c3fSmrg   } else if (MATCH(expr, txf_ms_pattern)) {
97701e04c3fSmrg      op = ir_txf_ms;
97801e04c3fSmrg   } else if (MATCH(expr, txs_pattern)) {
97901e04c3fSmrg      op = ir_txs;
98001e04c3fSmrg   } else if (MATCH(expr, tg4_pattern)) {
98101e04c3fSmrg      op = ir_tg4;
98201e04c3fSmrg   } else if (MATCH(expr, query_levels_pattern)) {
98301e04c3fSmrg      op = ir_query_levels;
98401e04c3fSmrg   } else if (MATCH(expr, texture_samples_pattern)) {
98501e04c3fSmrg      op = ir_texture_samples;
98601e04c3fSmrg   } else if (MATCH(expr, other_pattern)) {
98701e04c3fSmrg      op = ir_texture::get_opcode(tag->value());
98801e04c3fSmrg      if (op == (ir_texture_opcode) -1)
98901e04c3fSmrg	 return NULL;
99001e04c3fSmrg   } else {
99101e04c3fSmrg      ir_read_error(NULL, "unexpected texture pattern %s", tag->value());
99201e04c3fSmrg      return NULL;
99301e04c3fSmrg   }
99401e04c3fSmrg
99501e04c3fSmrg   ir_texture *tex = new(mem_ctx) ir_texture(op);
99601e04c3fSmrg
99701e04c3fSmrg   // Read return type
99801e04c3fSmrg   const glsl_type *type = read_type(s_type);
99901e04c3fSmrg   if (type == NULL) {
100001e04c3fSmrg      ir_read_error(NULL, "when reading type in (%s ...)",
100101e04c3fSmrg		    tex->opcode_string());
100201e04c3fSmrg      return NULL;
100301e04c3fSmrg   }
100401e04c3fSmrg
100501e04c3fSmrg   // Read sampler (must be a deref)
100601e04c3fSmrg   ir_dereference *sampler = read_dereference(s_sampler);
100701e04c3fSmrg   if (sampler == NULL) {
100801e04c3fSmrg      ir_read_error(NULL, "when reading sampler in (%s ...)",
100901e04c3fSmrg		    tex->opcode_string());
101001e04c3fSmrg      return NULL;
101101e04c3fSmrg   }
101201e04c3fSmrg   tex->set_sampler(sampler, type);
101301e04c3fSmrg
101401e04c3fSmrg   if (op != ir_txs) {
101501e04c3fSmrg      // Read coordinate (any rvalue)
101601e04c3fSmrg      tex->coordinate = read_rvalue(s_coord);
101701e04c3fSmrg      if (tex->coordinate == NULL) {
101801e04c3fSmrg	 ir_read_error(NULL, "when reading coordinate in (%s ...)",
101901e04c3fSmrg		       tex->opcode_string());
102001e04c3fSmrg	 return NULL;
102101e04c3fSmrg      }
102201e04c3fSmrg
102301e04c3fSmrg      if (op != ir_txf_ms && op != ir_lod) {
102401e04c3fSmrg         // Read texel offset - either 0 or an rvalue.
102501e04c3fSmrg         s_int *si_offset = SX_AS_INT(s_offset);
102601e04c3fSmrg         if (si_offset == NULL || si_offset->value() != 0) {
102701e04c3fSmrg            tex->offset = read_rvalue(s_offset);
102801e04c3fSmrg            if (tex->offset == NULL) {
102901e04c3fSmrg               ir_read_error(s_offset, "expected 0 or an expression");
103001e04c3fSmrg               return NULL;
103101e04c3fSmrg            }
103201e04c3fSmrg         }
103301e04c3fSmrg      }
103401e04c3fSmrg   }
103501e04c3fSmrg
103601e04c3fSmrg   if (op != ir_txf && op != ir_txf_ms &&
103701e04c3fSmrg       op != ir_txs && op != ir_lod && op != ir_tg4 &&
103801e04c3fSmrg       op != ir_query_levels && op != ir_texture_samples) {
103901e04c3fSmrg      s_int *proj_as_int = SX_AS_INT(s_proj);
104001e04c3fSmrg      if (proj_as_int && proj_as_int->value() == 1) {
104101e04c3fSmrg	 tex->projector = NULL;
104201e04c3fSmrg      } else {
104301e04c3fSmrg	 tex->projector = read_rvalue(s_proj);
104401e04c3fSmrg	 if (tex->projector == NULL) {
104501e04c3fSmrg	    ir_read_error(NULL, "when reading projective divide in (%s ..)",
104601e04c3fSmrg	                  tex->opcode_string());
104701e04c3fSmrg	    return NULL;
104801e04c3fSmrg	 }
104901e04c3fSmrg      }
105001e04c3fSmrg
105101e04c3fSmrg      if (s_shadow->subexpressions.is_empty()) {
105201e04c3fSmrg	 tex->shadow_comparator = NULL;
105301e04c3fSmrg      } else {
105401e04c3fSmrg	 tex->shadow_comparator = read_rvalue(s_shadow);
105501e04c3fSmrg	 if (tex->shadow_comparator == NULL) {
105601e04c3fSmrg	    ir_read_error(NULL, "when reading shadow comparator in (%s ..)",
105701e04c3fSmrg			  tex->opcode_string());
105801e04c3fSmrg	    return NULL;
105901e04c3fSmrg	 }
106001e04c3fSmrg      }
106101e04c3fSmrg   }
106201e04c3fSmrg
106301e04c3fSmrg   switch (op) {
106401e04c3fSmrg   case ir_txb:
106501e04c3fSmrg      tex->lod_info.bias = read_rvalue(s_lod);
106601e04c3fSmrg      if (tex->lod_info.bias == NULL) {
106701e04c3fSmrg	 ir_read_error(NULL, "when reading LOD bias in (txb ...)");
106801e04c3fSmrg	 return NULL;
106901e04c3fSmrg      }
107001e04c3fSmrg      break;
107101e04c3fSmrg   case ir_txl:
107201e04c3fSmrg   case ir_txf:
107301e04c3fSmrg   case ir_txs:
107401e04c3fSmrg      tex->lod_info.lod = read_rvalue(s_lod);
107501e04c3fSmrg      if (tex->lod_info.lod == NULL) {
107601e04c3fSmrg	 ir_read_error(NULL, "when reading LOD in (%s ...)",
107701e04c3fSmrg		       tex->opcode_string());
107801e04c3fSmrg	 return NULL;
107901e04c3fSmrg      }
108001e04c3fSmrg      break;
108101e04c3fSmrg   case ir_txf_ms:
108201e04c3fSmrg      tex->lod_info.sample_index = read_rvalue(s_sample_index);
108301e04c3fSmrg      if (tex->lod_info.sample_index == NULL) {
108401e04c3fSmrg         ir_read_error(NULL, "when reading sample_index in (txf_ms ...)");
108501e04c3fSmrg         return NULL;
108601e04c3fSmrg      }
108701e04c3fSmrg      break;
108801e04c3fSmrg   case ir_txd: {
108901e04c3fSmrg      s_expression *s_dx, *s_dy;
109001e04c3fSmrg      s_pattern dxdy_pat[] = { s_dx, s_dy };
109101e04c3fSmrg      if (!MATCH(s_lod, dxdy_pat)) {
109201e04c3fSmrg	 ir_read_error(s_lod, "expected (dPdx dPdy) in (txd ...)");
109301e04c3fSmrg	 return NULL;
109401e04c3fSmrg      }
109501e04c3fSmrg      tex->lod_info.grad.dPdx = read_rvalue(s_dx);
109601e04c3fSmrg      if (tex->lod_info.grad.dPdx == NULL) {
109701e04c3fSmrg	 ir_read_error(NULL, "when reading dPdx in (txd ...)");
109801e04c3fSmrg	 return NULL;
109901e04c3fSmrg      }
110001e04c3fSmrg      tex->lod_info.grad.dPdy = read_rvalue(s_dy);
110101e04c3fSmrg      if (tex->lod_info.grad.dPdy == NULL) {
110201e04c3fSmrg	 ir_read_error(NULL, "when reading dPdy in (txd ...)");
110301e04c3fSmrg	 return NULL;
110401e04c3fSmrg      }
110501e04c3fSmrg      break;
110601e04c3fSmrg   }
110701e04c3fSmrg   case ir_tg4:
110801e04c3fSmrg      tex->lod_info.component = read_rvalue(s_component);
110901e04c3fSmrg      if (tex->lod_info.component == NULL) {
111001e04c3fSmrg         ir_read_error(NULL, "when reading component in (tg4 ...)");
111101e04c3fSmrg         return NULL;
111201e04c3fSmrg      }
111301e04c3fSmrg      break;
111401e04c3fSmrg   default:
111501e04c3fSmrg      // tex and lod don't have any extra parameters.
111601e04c3fSmrg      break;
111701e04c3fSmrg   };
111801e04c3fSmrg   return tex;
111901e04c3fSmrg}
112001e04c3fSmrg
112101e04c3fSmrgir_emit_vertex *
112201e04c3fSmrgir_reader::read_emit_vertex(s_expression *expr)
112301e04c3fSmrg{
112401e04c3fSmrg   s_expression *s_stream = NULL;
112501e04c3fSmrg
112601e04c3fSmrg   s_pattern pat[] = { "emit-vertex", s_stream };
112701e04c3fSmrg
112801e04c3fSmrg   if (MATCH(expr, pat)) {
112901e04c3fSmrg      ir_rvalue *stream = read_dereference(s_stream);
113001e04c3fSmrg      if (stream == NULL) {
113101e04c3fSmrg         ir_read_error(NULL, "when reading stream info in emit-vertex");
113201e04c3fSmrg         return NULL;
113301e04c3fSmrg      }
113401e04c3fSmrg      return new(mem_ctx) ir_emit_vertex(stream);
113501e04c3fSmrg   }
113601e04c3fSmrg   ir_read_error(NULL, "when reading emit-vertex");
113701e04c3fSmrg   return NULL;
113801e04c3fSmrg}
113901e04c3fSmrg
114001e04c3fSmrgir_end_primitive *
114101e04c3fSmrgir_reader::read_end_primitive(s_expression *expr)
114201e04c3fSmrg{
114301e04c3fSmrg   s_expression *s_stream = NULL;
114401e04c3fSmrg
114501e04c3fSmrg   s_pattern pat[] = { "end-primitive", s_stream };
114601e04c3fSmrg
114701e04c3fSmrg   if (MATCH(expr, pat)) {
114801e04c3fSmrg      ir_rvalue *stream = read_dereference(s_stream);
114901e04c3fSmrg      if (stream == NULL) {
115001e04c3fSmrg         ir_read_error(NULL, "when reading stream info in end-primitive");
115101e04c3fSmrg         return NULL;
115201e04c3fSmrg      }
115301e04c3fSmrg      return new(mem_ctx) ir_end_primitive(stream);
115401e04c3fSmrg   }
115501e04c3fSmrg   ir_read_error(NULL, "when reading end-primitive");
115601e04c3fSmrg   return NULL;
115701e04c3fSmrg}
115801e04c3fSmrg
115901e04c3fSmrgir_barrier *
116001e04c3fSmrgir_reader::read_barrier(s_expression *expr)
116101e04c3fSmrg{
116201e04c3fSmrg   s_pattern pat[] = { "barrier" };
116301e04c3fSmrg
116401e04c3fSmrg   if (MATCH(expr, pat)) {
116501e04c3fSmrg      return new(mem_ctx) ir_barrier();
116601e04c3fSmrg   }
116701e04c3fSmrg   ir_read_error(NULL, "when reading barrier");
116801e04c3fSmrg   return NULL;
116901e04c3fSmrg}
1170