Store AST function call parameters in expressions
[mesa.git] / ast_to_hir.cpp
index 07d40e27d2401703d0570c704871eb2b98dea5d5..357683f0c3de5f84c2860a895ab6b4137c2a01c4 100644 (file)
@@ -761,11 +761,8 @@ ast_expression::hir(exec_list *instructions,
       error_emitted = true;
       break;
 
-   case ast_logic_and:
-   case ast_logic_xor:
-   case ast_logic_or:
+   case ast_logic_and: {
       op[0] = this->subexpressions[0]->hir(instructions, state);
-      op[1] = this->subexpressions[1]->hir(instructions, state);
 
       if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
         YYLTYPE loc = this->subexpressions[0]->get_location();
@@ -775,14 +772,125 @@ ast_expression::hir(exec_list *instructions,
         error_emitted = true;
       }
 
-      if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
-        YYLTYPE loc = this->subexpressions[1]->get_location();
+      ir_constant *op0_const = op[0]->constant_expression_value();
+      if (op0_const) {
+        if (op0_const->value.b[0]) {
+           op[1] = this->subexpressions[1]->hir(instructions, state);
+
+           if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+              YYLTYPE loc = this->subexpressions[1]->get_location();
+
+              _mesa_glsl_error(& loc, state,
+                               "RHS of `%s' must be scalar boolean",
+                               operator_string(this->oper));
+              error_emitted = true;
+           }
+           result = op[1];
+        } else {
+           result = op0_const;
+        }
+        type = glsl_type::bool_type;
+      } else {
+        ir_if *const stmt = new ir_if(op[0]);
+        instructions->push_tail(stmt);
+
+        op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state);
+
+        if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+           YYLTYPE loc = this->subexpressions[1]->get_location();
+
+           _mesa_glsl_error(& loc, state,
+                            "RHS of `%s' must be scalar boolean",
+                            operator_string(this->oper));
+           error_emitted = true;
+        }
+
+        ir_variable *const tmp = generate_temporary(glsl_type::bool_type,
+                                                    instructions, state);
+
+        ir_dereference *const then_deref = new ir_dereference(tmp);
+        ir_assignment *const then_assign =
+           new ir_assignment(then_deref, op[1], NULL);
+        stmt->then_instructions.push_tail(then_assign);
+
+        ir_dereference *const else_deref = new ir_dereference(tmp);
+        ir_assignment *const else_assign =
+           new ir_assignment(else_deref, new ir_constant(false), NULL);
+        stmt->else_instructions.push_tail(else_assign);
 
-        _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean",
+        result = new ir_dereference(tmp);
+        type = tmp->type;
+      }
+      break;
+   }
+
+   case ast_logic_or: {
+      op[0] = this->subexpressions[0]->hir(instructions, state);
+
+      if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
+        YYLTYPE loc = this->subexpressions[0]->get_location();
+
+        _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean",
                          operator_string(this->oper));
         error_emitted = true;
       }
 
+      ir_constant *op0_const = op[0]->constant_expression_value();
+      if (op0_const) {
+        if (op0_const->value.b[0]) {
+           result = op0_const;
+        } else {
+           op[1] = this->subexpressions[1]->hir(instructions, state);
+
+           if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+              YYLTYPE loc = this->subexpressions[1]->get_location();
+
+              _mesa_glsl_error(& loc, state,
+                               "RHS of `%s' must be scalar boolean",
+                               operator_string(this->oper));
+              error_emitted = true;
+           }
+           result = op[1];
+        }
+        type = glsl_type::bool_type;
+      } else {
+        ir_if *const stmt = new ir_if(op[0]);
+        instructions->push_tail(stmt);
+
+        ir_variable *const tmp = generate_temporary(glsl_type::bool_type,
+                                                    instructions, state);
+
+        op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state);
+
+        if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+           YYLTYPE loc = this->subexpressions[1]->get_location();
+
+           _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean",
+                            operator_string(this->oper));
+           error_emitted = true;
+        }
+
+        ir_dereference *const then_deref = new ir_dereference(tmp);
+        ir_assignment *const then_assign =
+           new ir_assignment(then_deref, new ir_constant(true), NULL);
+        stmt->then_instructions.push_tail(then_assign);
+
+        ir_dereference *const else_deref = new ir_dereference(tmp);
+        ir_assignment *const else_assign =
+           new ir_assignment(else_deref, op[1], NULL);
+        stmt->else_instructions.push_tail(else_assign);
+
+        result = new ir_dereference(tmp);
+        type = tmp->type;
+      }
+      break;
+   }
+
+   case ast_logic_xor:
+      op[0] = this->subexpressions[0]->hir(instructions, state);
+      op[1] = this->subexpressions[1]->hir(instructions, state);
+
+
       result = new ir_expression(operations[this->oper], glsl_type::bool_type,
                                 op[0], op[1]);
       type = glsl_type::bool_type;
@@ -1273,7 +1381,7 @@ ast_type_specifier::glsl_type(const char **name,
 {
    const struct glsl_type *type;
 
-   if (this->type_specifier == ast_struct) {
+   if ((this->type_specifier == ast_struct) && (this->type_name == NULL)) {
       /* FINISHME: Handle annonymous structures. */
       type = NULL;
    } else {
@@ -1338,6 +1446,15 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
    else
       var->mode = ir_var_auto;
 
+   if (qual->uniform)
+      var->shader_in = true;
+   if (qual->varying) {
+      if (qual->in)
+        var->shader_in = true;
+      if (qual->out)
+        var->shader_out = true;
+   }
+
    if (qual->flat)
       var->interpolation = ir_var_flat;
    else if (qual->noperspective)
@@ -1358,7 +1475,13 @@ ast_declarator_list::hir(exec_list *instructions,
    struct simple_node *ptr;
    const struct glsl_type *decl_type;
    const char *type_name = NULL;
+   ir_rvalue *result = NULL;
+   YYLTYPE loc = this->get_location();
 
+   /* The type specifier may contain a structure definition.  Process that
+    * before any of the variable declarations.
+    */
+   (void) this->type->specifier->hir(instructions, state);
 
    /* FINISHME: Handle vertex shader "invariant" declarations that do not
     * FINISHME: include a type.  These re-declare built-in variables to be
@@ -1366,12 +1489,27 @@ ast_declarator_list::hir(exec_list *instructions,
     */
 
    decl_type = this->type->specifier->glsl_type(& type_name, state);
+   if (is_empty_list(&this->declarations)) {
+      /* There are only two valid cases where the declaration list can be
+       * empty.
+       *
+       * 1. The declaration is setting the default precision of a built-in
+       *    type (e.g., 'precision highp vec4;').
+       *
+       * 2. Adding 'invariant' to an existing vertex shader output.
+       */
+
+      if (this->type->qualifier.invariant) {
+      } else if (decl_type != NULL) {
+      } else {
+           _mesa_glsl_error(& loc, state, "incomplete declaration");
+      }
+   }
 
    foreach (ptr, &this->declarations) {
       struct ast_declaration *const decl = (struct ast_declaration * )ptr;
       const struct glsl_type *var_type;
       struct ir_variable *var;
-      YYLTYPE loc = this->get_location();
 
       /* FINISHME: Emit a warning if a variable declaration shadows a
        * FINISHME: declaration at a higher scope.
@@ -1450,7 +1588,7 @@ ast_declarator_list::hir(exec_list *instructions,
             * FINISHME: required or not.
             */
 
-           if (var->type->array_size() <= earlier->max_array_access) {
+           if (var->type->array_size() <= (int)earlier->max_array_access) {
               YYLTYPE loc = this->get_location();
 
               _mesa_glsl_error(& loc, state, "array size must be > %u due to "
@@ -1619,8 +1757,8 @@ ast_declarator_list::hir(exec_list *instructions,
            bool temp = var->read_only;
            if (this->type->qualifier.constant)
               var->read_only = false;
-           (void) do_assignment(instructions, state, lhs, rhs,
-                                this->get_location());
+           result = do_assignment(instructions, state, lhs, rhs,
+                                  this->get_location());
            var->read_only = temp;
         }
       }
@@ -1650,9 +1788,17 @@ ast_declarator_list::hir(exec_list *instructions,
       assert(added_variable);
    }
 
-   /* Variable declarations do not have r-values.
+
+   /* Generally, variable declarations do not have r-values.  However,
+    * one is used for the declaration in
+    *
+    * while (bool b = some_condition()) {
+    *   ...
+    * }
+    *
+    * so we return the rvalue from the last seen declaration here.
     */
-   return NULL;
+   return result;
 }
 
 
@@ -1758,37 +1904,6 @@ ast_parameter_declarator::parameters_to_hir(struct simple_node *ast_parameters,
 }
 
 
-static bool
-parameter_lists_match(exec_list *list_a, exec_list *list_b)
-{
-   exec_list_iterator iter_a = list_a->iterator();
-   exec_list_iterator iter_b = list_b->iterator();
-
-   while (iter_a.has_next()) {
-      ir_variable *a = (ir_variable *)iter_a.get();
-      ir_variable *b = (ir_variable *)iter_b.get();
-
-      /* If all of the parameters from the other parameter list have been
-       * exhausted, the lists have different length and, by definition,
-       * do not match.
-       */
-      if (!iter_b.has_next())
-        return false;
-
-      /* If the types of the parameters do not match, the parameters lists
-       * are different.
-       */
-      if (a->type != b->type)
-        return false;
-
-      iter_a.next();
-      iter_b.next();
-   }
-
-   return true;
-}
-
-
 ir_rvalue *
 ast_function::hir(exec_list *instructions,
                  struct _mesa_glsl_parse_state *state)
@@ -1798,11 +1913,6 @@ ast_function::hir(exec_list *instructions,
    exec_list hir_parameters;
 
 
-   /* The prototype part of a function does not generate anything in the IR
-    * instruction stream.
-    */
-   (void) instructions;
-
    /* Convert the list of function parameters to HIR now so that they can be
     * used below to compare this function's signature with previously seen
     * signatures for functions with the same name.
@@ -1824,29 +1934,30 @@ ast_function::hir(exec_list *instructions,
    const char *const name = identifier;
    f = state->symbols->get_function(name);
    if (f != NULL) {
-      foreach_iter(exec_list_iterator, iter, *f) {
-        sig = (struct ir_function_signature *) iter.get();
+      ir_function_signature *sig = f->exact_matching_signature(&hir_parameters);
+      if (sig != NULL) {
+        const char *badvar = sig->qualifiers_match(&hir_parameters);
+        if (badvar != NULL) {
+           YYLTYPE loc = this->get_location();
 
-        /* Compare the parameter list of the function being defined to the
-         * existing function.  If the parameter lists match, then the return
-         * type must also match and the existing function must not have a
-         * definition.
-         */
-        if (parameter_lists_match(& hir_parameters, & sig->parameters)) {
-           /* FINISHME: Compare return types. */
+           _mesa_glsl_error(&loc, state, "function `%s' parameter `%s' "
+                            "qualifiers don't match prototype", name, badvar);
+        }
 
-           if (is_definition && (sig->definition != NULL)) {
-              YYLTYPE loc = this->get_location();
+        if (sig->return_type != return_type) {
+           YYLTYPE loc = this->get_location();
 
-              _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
-              sig = NULL;
-              break;
-           }
+           _mesa_glsl_error(&loc, state, "function `%s' return type doesn't "
+                            "match prototype", name);
         }
 
-        sig = NULL;
-      }
+        if (is_definition && sig->is_defined) {
+           YYLTYPE loc = this->get_location();
 
+           _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
+           sig = NULL;
+        }
+      }
    } else if (state->symbols->name_declared_this_scope(name)) {
       /* This function name shadows a non-function use of the same name.
        */
@@ -1858,6 +1969,9 @@ ast_function::hir(exec_list *instructions,
    } else {
       f = new ir_function(name);
       state->symbols->add_function(f->name, f);
+
+      /* Emit the new function header */
+      instructions->push_tail(f);
    }
 
    /* Verify the return type of main() */
@@ -1880,20 +1994,9 @@ ast_function::hir(exec_list *instructions,
    if (sig == NULL) {
       sig = new ir_function_signature(return_type);
       f->add_signature(sig);
-   } else if (is_definition) {
-      /* Destroy all of the previous parameter information.  The previous
-       * parameter information comes from the function prototype, and it can
-       * either include invalid parameter names or may not have names at all.
-       */
-      foreach_iter(exec_list_iterator, iter, sig->parameters) {
-        assert(((ir_instruction *) iter.get())->as_variable() != NULL);
-
-        iter.remove();
-        delete iter.get();
-      }
    }
 
-   hir_parameters.move_nodes_to(& sig->parameters);
+   sig->replace_parameters(&hir_parameters);
    signature = sig;
 
    /* Function declarations (prototypes) do not have r-values.
@@ -1914,24 +2017,14 @@ ast_function_definition::hir(exec_list *instructions,
    assert(state->current_function == NULL);
    state->current_function = signature;
 
-   ir_label *label = new ir_label(signature->function_name());
-   if (signature->definition == NULL) {
-      signature->definition = label;
-   }
-   instructions->push_tail(label);
-
    /* Duplicate parameters declared in the prototype as concrete variables.
     * Add these to the symbol table.
     */
    state->symbols->push_scope();
    foreach_iter(exec_list_iterator, iter, signature->parameters) {
-      ir_variable *const proto = ((ir_instruction *) iter.get())->as_variable();
-
-      assert(proto != NULL);
+      ir_variable *const var = ((ir_instruction *) iter.get())->as_variable();
 
-      ir_variable *const var = proto->clone();
-
-      instructions->push_tail(var);
+      assert(var != NULL);
 
       /* The only way a parameter would "exist" is if two parameters have
        * the same name.
@@ -1945,11 +2038,9 @@ ast_function_definition::hir(exec_list *instructions,
       }
    }
 
-   /* Convert the body of the function to HIR, and append the resulting
-    * instructions to the list that currently consists of the function label
-    * and the function parameters.
-    */
-   this->body->hir(instructions, state);
+   /* Convert the body of the function to HIR. */
+   this->body->hir(&signature->body, state);
+   signature->is_defined = true;
 
    state->symbols->pop_scope();
 
@@ -1980,7 +2071,7 @@ ast_jump_statement::hir(exec_list *instructions,
            _mesa_glsl_error(& loc, state,
                             "`return` with a value, in function `%s' "
                             "returning void",
-                            state->current_function->definition->label);
+                            state->current_function->function_name());
         }
 
         ir_expression *const ret = (ir_expression *)
@@ -2000,7 +2091,7 @@ ast_jump_statement::hir(exec_list *instructions,
            _mesa_glsl_error(& loc, state,
                             "`return' with no value, in function %s returning "
                             "non-void",
-                            state->current_function->definition->label);
+                            state->current_function->function_name());
         }
         inst = new ir_return;
       }
@@ -2142,9 +2233,9 @@ ir_rvalue *
 ast_iteration_statement::hir(exec_list *instructions,
                             struct _mesa_glsl_parse_state *state)
 {
-   /* For loops start a new scope, but while and do-while loops do not.
+   /* For-loops and while-loops start a new scope, but do-while loops do not.
     */
-   if (mode == ast_for)
+   if (mode != ast_do_while)
       state->symbols->push_scope();
 
    if (init_statement != NULL)
@@ -2175,7 +2266,7 @@ ast_iteration_statement::hir(exec_list *instructions,
    if (mode == ast_do_while)
       condition_to_hir(stmt, state);
 
-   if (mode == ast_for)
+   if (mode != ast_do_while)
       state->symbols->pop_scope();
 
    /* Restore previous nesting before returning.
@@ -2186,3 +2277,117 @@ ast_iteration_statement::hir(exec_list *instructions,
     */
    return NULL;
 }
+
+
+ir_rvalue *
+ast_type_specifier::hir(exec_list *instructions,
+                         struct _mesa_glsl_parse_state *state)
+{
+   if (this->structure != NULL)
+      return this->structure->hir(instructions, state);
+
+   return NULL;
+}
+
+
+ir_rvalue *
+ast_struct_specifier::hir(exec_list *instructions,
+                         struct _mesa_glsl_parse_state *state)
+{
+   simple_node *ptr;
+   unsigned decl_count = 0;
+
+   /* Make an initial pass over the list of structure fields to determine how
+    * many there are.  Each element in this list is an ast_declarator_list.
+    * This means that we actually need to count the number of elements in the
+    * 'declarations' list in each of the elements.
+    */
+   foreach (ptr, & this->declarations) {
+      ast_declarator_list *decl_list = (ast_declarator_list *) ptr;
+      simple_node *decl_ptr;
+
+      foreach (decl_ptr, & decl_list->declarations) {
+        decl_count++;
+      }
+   }
+
+
+   /* Allocate storage for the structure fields and process the field
+    * declarations.  As the declarations are processed, try to also convert
+    * the types to HIR.  This ensures that structure definitions embedded in
+    * other structure definitions are processed.
+    */
+   glsl_struct_field *const fields = (glsl_struct_field *)
+      malloc(sizeof(*fields) * decl_count);
+
+   unsigned i = 0;
+   foreach (ptr, & this->declarations) {
+      ast_declarator_list *decl_list = (ast_declarator_list *) ptr;
+      simple_node *decl_ptr;
+      const char *type_name;
+
+      decl_list->type->specifier->hir(instructions, state);
+
+      const glsl_type *decl_type =
+        decl_list->type->specifier->glsl_type(& type_name, state);
+
+      foreach (decl_ptr, & decl_list->declarations) {
+        ast_declaration *const decl = (ast_declaration *) decl_ptr;
+        const struct glsl_type *const field_type =
+           (decl->is_array)
+           ? process_array_type(decl_type, decl->array_size, state)
+           : decl_type;
+
+        fields[i].type = (field_type != NULL)
+           ? field_type : glsl_type::error_type;
+        fields[i].name = decl->identifier;
+        i++;
+      }
+   }
+
+   assert(i == decl_count);
+
+   const char *name;
+   if (this->name == NULL) {
+      static unsigned anon_count = 1;
+      char buf[32];
+
+      snprintf(buf, sizeof(buf), "#anon_struct_%04x", anon_count);
+      anon_count++;
+
+      name = strdup(buf);
+   } else {
+      name = this->name;
+   }
+
+   glsl_type *t = new glsl_type(fields, decl_count, name);
+
+   YYLTYPE loc = this->get_location();
+   if (!state->symbols->add_type(name, t)) {
+      _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
+   } else {
+      /* This logic is a bit tricky.  It is an error to declare a structure at
+       * global scope if there is also a function with the same name.
+       */
+      if ((state->current_function == NULL)
+         && (state->symbols->get_function(name) != NULL)) {
+        _mesa_glsl_error(& loc, state, "name `%s' previously defined", name);
+      } else {
+        t->generate_constructor(state->symbols);
+      }
+
+      const glsl_type **s = (const glsl_type **)
+        realloc(state->user_structures,
+                sizeof(state->user_structures[0]) *
+                (state->num_user_structures + 1));
+      if (s != NULL) {
+        s[state->num_user_structures] = t;
+        state->user_structures = s;
+        state->num_user_structures++;
+      }
+   }
+
+   /* Structure type definitions do not have r-values.
+    */
+   return NULL;
+}