Attach a pointer to variable names in LIR dumping.
[mesa.git] / ast_to_hir.cpp
index b8375b3e57af1569208afd2a39d0deaead165767..25bbe2f2defa9c1ea143168b9788b43cc98be13a 100644 (file)
@@ -48,7 +48,7 @@
  * As a result, my preference is to put as little C code as possible in the
  * parser (and lexer) sources.
  */
-#include <stdio.h>
+
 #include "main/imports.h"
 #include "glsl_symbol_table.h"
 #include "glsl_parser_extras.h"
@@ -509,10 +509,27 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
       }
    }
 
-   ir_instruction *tmp = new ir_assignment(lhs, rhs, NULL);
-   instructions->push_tail(tmp);
+   /* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
+    * but not post_inc) need the converted assigned value as an rvalue
+    * to handle things like:
+    *
+    * i = j += 1;
+    *
+    * So we always just store the computed value being assigned to a
+    * temporary and return a deref of that temporary.  If the rvalue
+    * ends up not being used, the temp will get copy-propagated out.
+    */
+   ir_variable *var = new ir_variable(rhs->type, "assignment_tmp");
+   instructions->push_tail(var);
+   instructions->push_tail(new ir_assignment(new ir_dereference_variable(var),
+                                            rhs,
+                                            NULL));
+
+   instructions->push_tail(new ir_assignment(lhs,
+                                            new ir_dereference_variable(var),
+                                            NULL));
 
-   return rhs;
+   return new ir_dereference_variable(var);
 }
 
 
@@ -536,25 +553,23 @@ generate_temporary(const glsl_type *type, exec_list *instructions,
 
 
 static ir_rvalue *
-get_lvalue_copy(exec_list *instructions, struct _mesa_glsl_parse_state *state,
-               ir_rvalue *lvalue, YYLTYPE loc)
+get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
 {
    ir_variable *var;
-   ir_rvalue *var_deref;
 
    /* FINISHME: Give unique names to the temporaries. */
-   var = new ir_variable(lvalue->type, "_internal_tmp");
+   var = new ir_variable(lvalue->type, "_post_incdec_tmp");
    var->mode = ir_var_auto;
 
-   var_deref = new ir_dereference_variable(var);
-   do_assignment(instructions, state, var_deref, lvalue, loc);
+   instructions->push_tail(new ir_assignment(new ir_dereference_variable(var),
+                                            lvalue, NULL));
 
    /* Once we've created this temporary, mark it read only so it's no
     * longer considered an lvalue.
     */
    var->read_only = true;
 
-   return var_deref;
+   return new ir_dereference_variable(var);
 }
 
 
@@ -932,7 +947,8 @@ ast_expression::hir(exec_list *instructions,
       ir_rvalue *temp_rhs = new ir_expression(operations[this->oper], type,
                                              op[0], op[1]);
 
-      result = do_assignment(instructions, state, op[0], temp_rhs,
+      result = do_assignment(instructions, state,
+                            (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
                             this->subexpressions[0]->get_location());
       type = result->type;
       error_emitted = (op[0]->type->is_error());
@@ -957,7 +973,8 @@ ast_expression::hir(exec_list *instructions,
       temp_rhs = new ir_expression(operations[this->oper], type,
                                   op[0], op[1]);
 
-      result = do_assignment(instructions, state, op[0], temp_rhs,
+      result = do_assignment(instructions, state,
+                            (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
                             this->subexpressions[0]->get_location());
       type = result->type;
       error_emitted = type->is_error();
@@ -1028,25 +1045,35 @@ ast_expression::hir(exec_list *instructions,
         type = op[1]->type;
       }
 
-      ir_variable *const tmp = generate_temporary(type,
-                                                 instructions, state);
+      ir_constant *cond_val = op[0]->constant_expression_value();
+      ir_constant *then_val = op[1]->constant_expression_value();
+      ir_constant *else_val = op[2]->constant_expression_value();
+
+      if (then_instructions.is_empty()
+         && else_instructions.is_empty()
+         && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) {
+        result = (cond_val->value.b[0]) ? then_val : else_val;
+      } else {
+        ir_variable *const tmp = generate_temporary(type,
+                                                    instructions, state);
 
-      ir_if *const stmt = new ir_if(op[0]);
-      instructions->push_tail(stmt);
+        ir_if *const stmt = new ir_if(op[0]);
+        instructions->push_tail(stmt);
 
-      then_instructions.move_nodes_to(& stmt->then_instructions);
-      ir_dereference *const then_deref = new ir_dereference_variable(tmp);
-      ir_assignment *const then_assign =
-        new ir_assignment(then_deref, op[1], NULL);
-      stmt->then_instructions.push_tail(then_assign);
+        then_instructions.move_nodes_to(& stmt->then_instructions);
+        ir_dereference *const then_deref = new ir_dereference_variable(tmp);
+        ir_assignment *const then_assign =
+           new ir_assignment(then_deref, op[1], NULL);
+        stmt->then_instructions.push_tail(then_assign);
 
-      else_instructions.move_nodes_to(& stmt->else_instructions);
-      ir_dereference *const else_deref = new ir_dereference_variable(tmp);
-      ir_assignment *const else_assign =
-        new ir_assignment(else_deref, op[2], NULL);
-      stmt->else_instructions.push_tail(else_assign);
+        else_instructions.move_nodes_to(& stmt->else_instructions);
+        ir_dereference *const else_deref = new ir_dereference_variable(tmp);
+        ir_assignment *const else_assign =
+           new ir_assignment(else_deref, op[2], NULL);
+        stmt->else_instructions.push_tail(else_assign);
 
-      result = new ir_dereference_variable(tmp);
+        result = new ir_dereference_variable(tmp);
+      }
       break;
    }
 
@@ -1064,7 +1091,8 @@ ast_expression::hir(exec_list *instructions,
       temp_rhs = new ir_expression(operations[this->oper], type,
                                   op[0], op[1]);
 
-      result = do_assignment(instructions, state, op[0], temp_rhs,
+      result = do_assignment(instructions, state,
+                            (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
                             this->subexpressions[0]->get_location());
       type = result->type;
       error_emitted = op[0]->type->is_error();
@@ -1090,10 +1118,10 @@ ast_expression::hir(exec_list *instructions,
       /* Get a temporary of a copy of the lvalue before it's modified.
        * This may get thrown away later.
        */
-      result = get_lvalue_copy(instructions, state, op[0],
-                              this->subexpressions[0]->get_location());
+      result = get_lvalue_copy(instructions, (ir_rvalue *)op[0]->clone(NULL));
 
-      (void)do_assignment(instructions, state, op[0], temp_rhs,
+      (void)do_assignment(instructions, state,
+                         (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
                          this->subexpressions[0]->get_location());
 
       type = result->type;
@@ -1247,22 +1275,22 @@ ast_expression::hir(exec_list *instructions,
 
    case ast_int_constant:
       type = glsl_type::int_type;
-      result = new ir_constant(type, & this->primary_expression);
+      result = new ir_constant(this->primary_expression.int_constant);
       break;
 
    case ast_uint_constant:
       type = glsl_type::uint_type;
-      result = new ir_constant(type, & this->primary_expression);
+      result = new ir_constant(this->primary_expression.uint_constant);
       break;
 
    case ast_float_constant:
       type = glsl_type::float_type;
-      result = new ir_constant(type, & this->primary_expression);
+      result = new ir_constant(this->primary_expression.float_constant);
       break;
 
    case ast_bool_constant:
       type = glsl_type::bool_type;
-      result = new ir_constant(type, & this->primary_expression);
+      result = new ir_constant(bool(this->primary_expression.bool_constant));
       break;
 
    case ast_sequence: {
@@ -1461,11 +1489,27 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
 
    if (qual->uniform)
       var->shader_in = true;
-   if (qual->varying) {
-      if (qual->in)
+
+   /* Any 'in' or 'inout' variables at global scope must be marked as being
+    * shader inputs.  Likewise, any 'out' or 'inout' variables at global scope
+    * must be marked as being shader outputs.
+    */
+   if (state->current_function == NULL) {
+      switch (var->mode) {
+      case ir_var_in:
+      case ir_var_uniform:
+        var->shader_in = true;
+        break;
+      case ir_var_out:
+        var->shader_out = true;
+        break;
+      case ir_var_inout:
         var->shader_in = true;
-      if (qual->out)
         var->shader_out = true;
+        break;
+      default:
+        break;
+      }
    }
 
    if (qual->flat)
@@ -1748,15 +1792,17 @@ ast_declarator_list::hir(exec_list *instructions,
         ir_dereference *const lhs = new ir_dereference_variable(var);
         ir_rvalue *rhs = decl->initializer->hir(instructions, state);
 
-        /* Calculate the constant value if this is a const
+        /* Calculate the constant value if this is a const or uniform
          * declaration.
          */
-        if (this->type->qualifier.constant) {
+        if (this->type->qualifier.constant || this->type->qualifier.uniform) {
            ir_constant *constant_value = rhs->constant_expression_value();
            if (!constant_value) {
               _mesa_glsl_error(& initializer_loc, state,
-                               "initializer of const variable `%s' must be a "
+                               "initializer of %s variable `%s' must be a "
                                "constant expression",
+                               (this->type->qualifier.constant)
+                               ? "const" : "uniform",
                                decl->identifier);
            } else {
               rhs = constant_value;
@@ -1768,8 +1814,12 @@ ast_declarator_list::hir(exec_list *instructions,
            bool temp = var->read_only;
            if (this->type->qualifier.constant)
               var->read_only = false;
-           result = do_assignment(instructions, state, lhs, rhs,
-                                  this->get_location());
+
+           /* Never emit code to initialize a uniform.
+            */
+           if (!this->type->qualifier.uniform)
+              result = do_assignment(instructions, state, lhs, rhs,
+                                     this->get_location());
            var->read_only = temp;
         }
       }
@@ -2139,8 +2189,7 @@ ast_jump_statement::hir(exec_list *instructions,
 
         if (loop != NULL) {
            ir_loop_jump *const jump =
-              new ir_loop_jump(loop,
-                               (mode == ast_break)
+              new ir_loop_jump((mode == ast_break)
                                ? ir_loop_jump::jump_break
                                : ir_loop_jump::jump_continue);
            instructions->push_tail(jump);
@@ -2219,7 +2268,7 @@ ast_iteration_statement::condition_to_hir(ir_loop *stmt,
         ir_if *const if_stmt = new ir_if(not_cond);
 
         ir_jump *const break_stmt =
-           new ir_loop_jump(stmt, ir_loop_jump::jump_break);
+           new ir_loop_jump(ir_loop_jump::jump_break);
 
         if_stmt->then_instructions.push_tail(break_stmt);
         stmt->body_instructions.push_tail(if_stmt);