glsl: Convert ir_call to be a statement rather than a value.
authorKenneth Graunke <kenneth@whitecape.org>
Tue, 20 Mar 2012 22:56:37 +0000 (15:56 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Mon, 2 Apr 2012 21:15:41 +0000 (14:15 -0700)
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>
20 files changed:
src/glsl/ast_function.cpp
src/glsl/builtins/ir/acos.ir
src/glsl/builtins/ir/atan.ir
src/glsl/ir.cpp
src/glsl/ir.h
src/glsl/ir_basic_block.cpp
src/glsl/ir_clone.cpp
src/glsl/ir_constant_expression.cpp
src/glsl/ir_expression_flattening.cpp
src/glsl/ir_hv_accept.cpp
src/glsl/ir_print_visitor.cpp
src/glsl/ir_reader.cpp
src/glsl/ir_validate.cpp
src/glsl/linker.cpp
src/glsl/opt_constant_folding.cpp
src/glsl/opt_constant_variable.cpp
src/glsl/opt_dead_code.cpp
src/glsl/opt_dead_code_local.cpp
src/glsl/opt_function_inlining.cpp
src/glsl/opt_tree_grafting.cpp

index 934bc5e891a1426ee2b44b2893114e1708e70a18..dfdbc55c575fc7abd56c6b51a05da2c239116adc 100644 (file)
@@ -269,29 +269,21 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
       formal_iter.next();
    }
 
-   /* Always insert the call in the instruction stream, and return a deref
-    * of its return val if it returns a value, since we don't know if
-    * the rvalue is going to be assigned to anything or not.
+   /* If the function call is a constant expression, don't generate any
+    * instructions; just generate an ir_constant.
     *
-    * Also insert any out parameter conversions after the call.
+    * Function calls were first allowed to be constant expressions in GLSL 1.20.
     */
-   ir_call *call = new(ctx) ir_call(sig, actual_parameters);
-   ir_dereference_variable *deref;
-   if (!sig->return_type->is_void()) {
-      /* If the function call is a constant expression, don't
-       * generate the instructions to call it; just generate an
-       * ir_constant representing the constant value.
-       *
-       * Function calls can only be constant expressions starting
-       * in GLSL 1.20.
-       */
-      if (state->language_version >= 120) {
-        ir_constant *const_val = call->constant_expression_value();
-        if (const_val) {
-           return const_val;
-        }
+   if (state->language_version >= 120) {
+      ir_constant *value = sig->constant_expression_value(actual_parameters);
+      if (value != NULL) {
+        return value;
       }
+   }
 
+   ir_dereference_variable *deref = NULL;
+   if (!sig->return_type->is_void()) {
+      /* Create a new temporary to hold the return value. */
       ir_variable *var;
 
       var = new(ctx) ir_variable(sig->return_type,
@@ -301,18 +293,14 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
       instructions->push_tail(var);
 
       deref = new(ctx) ir_dereference_variable(var);
-      ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
-      instructions->push_tail(assign);
-      *call_ir = call;
-
-      deref = new(ctx) ir_dereference_variable(var);
-   } else {
-      instructions->push_tail(call);
-      *call_ir = call;
-      deref = NULL;
    }
+   ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters);
+   instructions->push_tail(call);
+
+   /* Also emit any necessary out-parameter conversions. */
    instructions->append_list(&post_call_conversions);
-   return deref;
+
+   return deref ? deref->clone(ctx, NULL) : NULL;
 }
 
 /**
index d1cfebeff8a22f3a55761ccf268e71cc5afdd0ae..f0078f884e7709a2b2c4261ac4385956fd34d764 100644 (file)
@@ -2,21 +2,28 @@
    (signature float
      (parameters
        (declare (in) float x))
-     ((return (expression float - (constant float (1.5707963))
-                                  (call asin ((var_ref x)))))))
+     ((declare () float s)
+      (call asin (var_ref s) ((var_ref x)))
+      (return (expression float - (constant float (1.5707963)) (var_ref s)))))
+
    (signature vec2
      (parameters
        (declare (in) vec2 x))
-     ((return (expression vec2 - (constant float (1.5707963))
-                                 (call asin ((var_ref x)))))))
+     ((declare () vec2 s)
+      (call asin (var_ref s) ((var_ref x)))
+      (return (expression vec2 - (constant float (1.5707963)) (var_ref s)))))
+
    (signature vec3
      (parameters
        (declare (in) vec3 x))
-     ((return (expression vec3 - (constant float (1.5707963))
-                                 (call asin ((var_ref x)))))))
+     ((declare () vec3 s)
+      (call asin (var_ref s) ((var_ref x)))
+      (return (expression vec3 - (constant float (1.5707963)) (var_ref s)))))
+
    (signature vec4
      (parameters
        (declare (in) vec4 x))
-     ((return (expression vec4 - (constant float (1.5707963))
-                                 (call asin ((var_ref x)))))))
+     ((declare () vec4 s)
+      (call asin (var_ref s) ((var_ref x)))
+      (return (expression vec4 - (constant float (1.5707963)) (var_ref s)))))
 ))
index 7b5ea13c6ba6da4c69b5c9bd766c123ab52d62a5..a9dc08e972771341b274cd44e459e4e949537db6 100644 (file)
@@ -2,50 +2,62 @@
    (signature float
      (parameters
        (declare (in) float y_over_x))
-     ((return (call asin ((expression float *
+     ((declare () float s)
+      (call asin (var_ref s)
+                         ((expression float *
                           (var_ref y_over_x)
                           (expression float rsq
                            (expression float +
                             (expression float *
                              (var_ref y_over_x)
                              (var_ref y_over_x))
-                            (constant float (1.0))))))))))
+                            (constant float (1.0)))))))
+      (return (var_ref s))))
 
    (signature vec2
      (parameters
        (declare (in) vec2 y_over_x))
-     ((return (call asin ((expression vec2 *
+     ((declare () vec2 s)
+      (call asin (var_ref s)
+                         ((expression vec2 *
                           (var_ref y_over_x)
                           (expression vec2 rsq
                            (expression vec2 +
                             (expression vec2 *
                              (var_ref y_over_x)
                              (var_ref y_over_x))
-                            (constant float (1.0))))))))))
+                            (constant float (1.0)))))))
+      (return (var_ref s))))
 
    (signature vec3
      (parameters
        (declare (in) vec3 y_over_x))
-     ((return (call asin ((expression vec3 *
+     ((declare () vec3 s)
+      (call asin (var_ref s)
+                         ((expression vec3 *
                           (var_ref y_over_x)
                           (expression vec3 rsq
                            (expression vec3 +
                             (expression vec3 *
                              (var_ref y_over_x)
                              (var_ref y_over_x))
-                            (constant float (1.0))))))))))
+                            (constant float (1.0)))))))
+      (return (var_ref s))))
 
    (signature vec4
      (parameters
        (declare (in) vec4 y_over_x))
-     ((return (call asin ((expression vec4 *
+     ((declare () vec4 s)
+      (call asin (var_ref s)
+                         ((expression vec4 *
                           (var_ref y_over_x)
                           (expression vec4 rsq
                            (expression vec4 +
                             (expression vec4 *
                              (var_ref y_over_x)
                              (var_ref y_over_x))
-                            (constant float (1.0))))))))))
+                            (constant float (1.0)))))))
+      (return (var_ref s))))
 
   (signature float
     (parameters
@@ -57,7 +69,7 @@
       (if (expression bool >
            (expression float abs (var_ref x))
            (expression float * (constant float (1.0e-8)) (expression float abs (var_ref y)))) (
-        (assign (x) (var_ref r) (call atan ((expression float / (var_ref y) (var_ref x)))))
+        (call atan (var_ref r) ((expression float / (var_ref y) (var_ref x))))
         (if (expression bool < (var_ref x) (constant float (0.000000)) ) (
           (if (expression bool >= (var_ref y) (constant float (0.000000)) )
               ((assign (x) (var_ref r) (expression float + (var_ref r) (constant float (3.141593)))))
        (declare (in) vec2 y)
        (declare (in) vec2 x))
      ((declare () vec2 r)
-      (assign (x) (var_ref r)
-             (call atan ((swiz x (var_ref y))
-                         (swiz x (var_ref x)))))
-      (assign (y) (var_ref r)
-             (call atan ((swiz y (var_ref y))
-                         (swiz y (var_ref x)))))
+      (declare () float temp)
+      (call atan (var_ref temp) ((swiz x (var_ref y)) (swiz x (var_ref x))))
+      (assign (x) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz y (var_ref y)) (swiz y (var_ref x))))
+      (assign (y) (var_ref r) (var_ref temp))
       (return (var_ref r))))
 
    (signature vec3
        (declare (in) vec3 y)
        (declare (in) vec3 x))
      ((declare () vec3 r)
-      (assign (x) (var_ref r)
-             (call atan ((swiz x (var_ref y))
-                         (swiz x (var_ref x)))))
-      (assign (y) (var_ref r)
-             (call atan ((swiz y (var_ref y))
-                         (swiz y (var_ref x)))))
-      (assign (z) (var_ref r)
-             (call atan ((swiz z (var_ref y))
-                         (swiz z (var_ref x)))))
+      (declare () float temp)
+      (call atan (var_ref temp) ((swiz x (var_ref y)) (swiz x (var_ref x))))
+      (assign (x) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz y (var_ref y)) (swiz y (var_ref x))))
+      (assign (y) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz z (var_ref y)) (swiz z (var_ref x))))
+      (assign (z) (var_ref r) (var_ref temp))
       (return (var_ref r))))
 
    (signature vec4
        (declare (in) vec4 y)
        (declare (in) vec4 x))
      ((declare () vec4 r)
-      (assign (x) (var_ref r)
-             (call atan ((swiz x (var_ref y))
-                         (swiz x (var_ref x)))))
-      (assign (y) (var_ref r)
-             (call atan ((swiz y (var_ref y))
-                         (swiz y (var_ref x)))))
-      (assign (z) (var_ref r)
-             (call atan ((swiz z (var_ref y))
-                         (swiz z (var_ref x)))))
-      (assign (w) (var_ref r)
-             (call atan ((swiz w (var_ref y))
-                         (swiz w (var_ref x)))))
-      (return (var_ref r)))))
+      (declare () float temp)
+      (call atan (var_ref temp) ((swiz x (var_ref y)) (swiz x (var_ref x))))
+      (assign (x) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz y (var_ref y)) (swiz y (var_ref x))))
+      (assign (y) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz z (var_ref y)) (swiz z (var_ref x))))
+      (assign (z) (var_ref r) (var_ref temp))
+      (call atan (var_ref temp) ((swiz w (var_ref y)) (swiz w (var_ref x))))
+      (assign (w) (var_ref r) (var_ref temp))
+      (return (var_ref r))))
 
 ))
index b497ff154ba80f02f45dc832a14c32e06edba31a..3595e742f785352e69890938bb4de96f02dceb92 100644 (file)
@@ -1470,8 +1470,6 @@ ir_rvalue::error_value(void *mem_ctx)
 void
 ir_call::set_callee(ir_function_signature *sig)
 {
-   assert((this->type == NULL) || (this->type == sig->return_type));
-
    this->callee = sig;
 }
 
index bb4f7759b300e8d54cdd473303c6dd36b1cf380f..054e2acaadb432e441fbd12f212f0c97bcb1b102 100644 (file)
@@ -1023,16 +1023,18 @@ public:
 
 
 /**
- * IR instruction representing a function call
+ * HIR instruction representing a high-level function call, containing a list
+ * of parameters and returning a value in the supplied temporary.
  */
-class ir_call : public ir_rvalue {
+class ir_call : public ir_instruction {
 public:
-   ir_call(ir_function_signature *callee, exec_list *actual_parameters)
-      : callee(callee)
+   ir_call(ir_function_signature *callee,
+          ir_dereference_variable *return_deref,
+          exec_list *actual_parameters)
+      : return_deref(return_deref), callee(callee)
    {
       ir_type = ir_type_call;
       assert(callee->return_type != NULL);
-      type = callee->return_type;
       actual_parameters->move_nodes_to(& this->actual_parameters);
       this->use_builtin = callee->is_builtin;
    }
@@ -1084,9 +1086,15 @@ public:
 
    /**
     * Generates an inline version of the function before @ir,
-    * returning the return value of the function.
+    * storing the return value in return_deref.
     */
-   ir_rvalue *generate_inline(ir_instruction *ir);
+   void generate_inline(ir_instruction *ir);
+
+   /**
+    * Storage for the function's return value.
+    * This must be NULL if the return type is void.
+    */
+   ir_dereference_variable *return_deref;
 
    /* List of ir_rvalue of paramaters passed in this call. */
    exec_list actual_parameters;
index a8338259620501dd782e26115658c25e70b5e2c8..86e0cf795a13b903eba4a242a0b35c2ebe240c54 100644 (file)
 #include "ir_basic_block.h"
 #include "glsl_types.h"
 
-class ir_has_call_visitor : public ir_hierarchical_visitor {
-public:
-   ir_has_call_visitor()
-   {
-      has_call = false;
-   }
-
-   virtual ir_visitor_status visit_enter(ir_call *ir)
-   {
-      (void) ir;
-      has_call = true;
-      return visit_stop;
-   }
-
-   bool has_call;
-};
-
-bool
-ir_has_call(ir_instruction *ir)
-{
-   ir_has_call_visitor v;
-   ir->accept(&v);
-   return v.has_call;
-}
-
 /**
  * Calls a user function for every basic block in the instruction stream.
  *
@@ -122,24 +97,6 @@ void call_for_basic_blocks(exec_list *instructions,
 
            call_for_basic_blocks(&ir_sig->body, callback, data);
         }
-      } else if (ir->as_assignment()) {
-        /* If there's a call in the expression tree being assigned,
-         * then that ends the BB too.
-         *
-         * The assumption is that any consumer of the basic block
-         * walker is fine with the fact that the call is somewhere in
-         * the tree even if portions of the tree may be evaluated
-         * after the call.
-         *
-         * A consumer that has an issue with this could not process
-         * the last instruction of the basic block.  If doing so,
-         * expression flattener may be useful before using the basic
-         * block finder to get more maximal basic blocks out.
-         */
-        if (ir_has_call(ir)) {
-           callback(leader, ir, data);
-           leader = NULL;
-        }
       }
       last = ir;
    }
index b6d0e8aa4a3fa9b0c9121647a792ad4b6945dade..8a9701c94966cdb2147f6edad607eaced98bddc5 100644 (file)
@@ -167,6 +167,10 @@ ir_loop::clone(void *mem_ctx, struct hash_table *ht) const
 ir_call *
 ir_call::clone(void *mem_ctx, struct hash_table *ht) const
 {
+   ir_dereference_variable *new_return_ref = NULL;
+   if (this->return_deref != NULL)
+      new_return_ref = this->return_deref->clone(mem_ctx, ht);
+
    exec_list new_parameters;
 
    foreach_iter(exec_list_iterator, iter, this->actual_parameters) {
@@ -174,7 +178,7 @@ ir_call::clone(void *mem_ctx, struct hash_table *ht) const
       new_parameters.push_tail(ir->clone(mem_ctx, ht));
    }
 
-   return new(mem_ctx) ir_call(this->callee, &new_parameters);
+   return new(mem_ctx) ir_call(this->callee, new_return_ref, &new_parameters);
 }
 
 ir_expression *
index aa47c08d88a8509d488b7b696409fb4bae4c575e..4e1714a842087bbf338d886811f9d7901c03b88f 100644 (file)
@@ -1024,9 +1024,6 @@ ir_constant::constant_expression_value()
 ir_constant *
 ir_call::constant_expression_value()
 {
-   if (this->type == glsl_type::error_type)
-      return NULL;
-
    return this->callee->constant_expression_value(&this->actual_parameters);
 }
 
index bd4ac67bc1a72aa2269662876cf6292a61f80e7f..b44e68ca364cedf6ecedde9db039faa3162b7cc6 100644 (file)
  *
  * This is used for breaking down matrix operations, where it's easier to
  * create a temporary and work on each of its vector components individually.
- *
- * It is also used for automatic function inlining, where we want to take
- * an expression containing a call and move the call out to its own
- * assignment so that we can inline it at the appropriate place in the
- * instruction stream.
  */
 
 #include "ir.h"
index c3be0521598e8e2232bae0bde899648d44b16ab7..3ce8959245db8fa3eaca638a52d8c799c21249cf 100644 (file)
@@ -333,6 +333,14 @@ ir_call::accept(ir_hierarchical_visitor *v)
    if (s != visit_continue)
       return (s == visit_continue_with_parent) ? visit_continue : s;
 
+   if (this->return_deref != NULL) {
+      v->in_assignee = true;
+      s = this->return_deref->accept(v);
+      v->in_assignee = false;
+      if (s != visit_continue)
+        return (s == visit_continue_with_parent) ? visit_continue : s;
+   }
+
    s = visit_list_elements(v, &this->actual_parameters, false);
    if (s == visit_stop)
       return s;
index 78ba0ba9c810fc587d51d2b00da0b21de3f23188..8aa26e5d018f4239e8e44154bf92e41c80679b41 100644 (file)
@@ -408,7 +408,10 @@ void ir_print_visitor::visit(ir_constant *ir)
 void
 ir_print_visitor::visit(ir_call *ir)
 {
-   printf("(call %s (", ir->callee_name());
+   printf("(call %s ", ir->callee_name());
+   if (ir->return_deref)
+      ir->return_deref->accept(this);
+   printf(" (");
    foreach_iter(exec_list_iterator, iter, *ir) {
       ir_instruction *const inst = (ir_instruction *) iter.get();
 
index e66ae4704385371ef73a57e2989c3cfe5e6d2f13..7ce683ef7d33c70ffd287c2c884a5f8ea406d3e6 100644 (file)
@@ -51,11 +51,11 @@ private:
    ir_variable *read_declaration(s_expression *);
    ir_if *read_if(s_expression *, ir_loop *);
    ir_loop *read_loop(s_expression *);
+   ir_call *read_call(s_expression *);
    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_call *read_call(s_expression *);
    ir_swizzle *read_swizzle(s_expression *);
    ir_constant *read_constant(s_expression *);
    ir_texture *read_texture(s_expression *);
@@ -349,6 +349,8 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
       inst = read_if(list, loop_ctx);
    } else if (strcmp(tag->value(), "loop") == 0) {
       inst = read_loop(list);
+   } else if (strcmp(tag->value(), "call") == 0) {
+      inst = read_call(list);
    } else if (strcmp(tag->value(), "return") == 0) {
       inst = read_return(list);
    } else if (strcmp(tag->value(), "function") == 0) {
@@ -522,8 +524,6 @@ ir_reader::read_rvalue(s_expression *expr)
       rvalue = read_swizzle(list);
    } else if (strcmp(tag->value(), "expression") == 0) {
       rvalue = read_expression(list);
-   } else if (strcmp(tag->value(), "call") == 0) {
-      rvalue = read_call(list);
    } else if (strcmp(tag->value(), "constant") == 0) {
       rvalue = read_constant(list);
    } else {
@@ -611,10 +611,20 @@ ir_reader::read_call(s_expression *expr)
 {
    s_symbol *name;
    s_list *params;
+   s_list *s_return = NULL;
 
-   s_pattern pat[] = { "call", name, params };
-   if (!MATCH(expr, pat)) {
-      ir_read_error(expr, "expected (call <name> (<param> ...))");
+   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> ...))");
       return NULL;
    }
 
@@ -644,7 +654,15 @@ ir_reader::read_call(s_expression *expr)
       return NULL;
    }
 
-   return new(mem_ctx) ir_call(callee, &parameters);
+   if (callee->return_type == glsl_type::void_type && return_deref) {
+      ir_read_error(expr, "call has return value storage but void type");
+      return NULL;
+   } else if (callee->return_type != glsl_type::void_type && !return_deref) {
+      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, &parameters);
 }
 
 ir_expression *
index 101d9992da23998af80da88ca5ed50725750ccb0..66dd84f73f34028abeb4f77987389064a0f0a0fe 100644 (file)
@@ -548,6 +548,17 @@ ir_validate::visit_enter(ir_call *ir)
       abort();
    }
 
+   if (ir->return_deref) {
+      if (ir->return_deref->type != callee->return_type) {
+        printf("callee type %s does not match return storage type %s\n",
+               callee->return_type->name, ir->return_deref->type->name);
+        abort();
+      }
+   } else if (callee->return_type != glsl_type::void_type) {
+      printf("ir_call has non-void callee but no return storage\n");
+      abort();
+   }
+
    const exec_node *formal_param_node = callee->parameters.head;
    const exec_node *actual_param_node = ir->actual_parameters.head;
    while (true) {
index 09ffdff63fbb1d1700f8521057c47adca8c7b978..d56eb97e45ae798f588b9710de2ebad70443efd7 100644 (file)
@@ -117,6 +117,15 @@ public:
         sig_iter.next();
       }
 
+      if (ir->return_deref != NULL) {
+        ir_variable *const var = ir->return_deref->variable_referenced();
+
+        if (strcmp(name, var->name) == 0) {
+           found = true;
+           return visit_stop;
+        }
+      }
+
       return visit_continue_with_parent;
    }
 
@@ -830,6 +839,7 @@ move_non_declarations(exec_list *instructions, exec_node *last,
         continue;
 
       assert(inst->as_assignment()
+             || inst->as_call()
             || ((var != NULL) && (var->mode == ir_var_temporary)));
 
       if (make_copies) {
index 599b21525de8a4c94b76b47ac929fd0d35b138bc..db8cd5cee6d920a83cc2b143bb4d57f9bdc4dc52 100644 (file)
@@ -117,6 +117,7 @@ ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
 ir_visitor_status
 ir_constant_folding_visitor::visit_enter(ir_call *ir)
 {
+   /* Attempt to constant fold parameters */
    exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
    foreach_iter(exec_list_iterator, iter, *ir) {
       ir_rvalue *param_rval = (ir_rvalue *)iter.get();
@@ -133,6 +134,15 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir)
       sig_iter.next();
    }
 
+   /* Next, see if the call can be replaced with an assignment of a constant */
+   ir_constant *const_val = ir->constant_expression_value();
+
+   if (const_val != NULL) {
+      ir_assignment *assignment =
+        new(ralloc_parent(ir)) ir_assignment(ir->return_deref, const_val);
+      ir->replace_with(assignment);
+   }
+
    return visit_continue_with_parent;
 }
 
index 3fa7c3badc804c4ae5aa6d55d67876bffb18fc1d..18c28018234c16ce47c2c3eab32a30156583bba5 100644 (file)
@@ -127,6 +127,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
 ir_visitor_status
 ir_constant_variable_visitor::visit_enter(ir_call *ir)
 {
+   /* Mark any out parameters as assigned to */
    exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
    foreach_iter(exec_list_iterator, iter, *ir) {
       ir_rvalue *param_rval = (ir_rvalue *)iter.get();
@@ -143,6 +144,17 @@ ir_constant_variable_visitor::visit_enter(ir_call *ir)
       }
       sig_iter.next();
    }
+
+   /* Mark the return storage as having been assigned to */
+   if (ir->return_deref != NULL) {
+      ir_variable *var = ir->return_deref->variable_referenced();
+      struct assignment_entry *entry;
+
+      assert(var);
+      entry = get_assignment_entry(var, &this->list);
+      entry->assignment_count++;
+   }
+
    return visit_continue;
 }
 
index 22c7af1c20a73e12eaaca34cd6b1ec6d8f6f8264..0578f1737b050becd8405eddbcc58f8bc16ffe05 100644 (file)
@@ -78,8 +78,7 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
          * Don't do so if it's a shader output, though.
          */
         if (entry->var->mode != ir_var_out &&
-            entry->var->mode != ir_var_inout &&
-            !ir_has_call(entry->assign)) {
+            entry->var->mode != ir_var_inout) {
            entry->assign->remove();
            progress = true;
 
index 39962bd602ef8ba89a2ad34eba903d82cdbdc437..a81a38fff0fb097077a85a847870a3a7b511f32a 100644 (file)
@@ -149,12 +149,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
       }
    }
 
-   /* Add this instruction to the assignment list available to be removed.
-    * But not if the assignment has other side effects.
-    */
-   if (ir_has_call(ir))
-      return progress;
-
+   /* Add this instruction to the assignment list available to be removed. */
    assignment_entry *entry = new(ctx) assignment_entry(var, ir);
    assignments->push_tail(entry);
 
index ec8b72c632fdf53f92ecd9c894a3918ec0833c0a..4ff4d97d9bcb707e0474f9f2d49532249a59ed8a 100644 (file)
@@ -53,7 +53,6 @@ public:
 
    virtual ir_visitor_status visit_enter(ir_expression *);
    virtual ir_visitor_status visit_enter(ir_call *);
-   virtual ir_visitor_status visit_enter(ir_assignment *);
    virtual ir_visitor_status visit_enter(ir_return *);
    virtual ir_visitor_status visit_enter(ir_texture *);
    virtual ir_visitor_status visit_enter(ir_swizzle *);
@@ -62,24 +61,11 @@ public:
 };
 
 
-bool
-automatic_inlining_predicate(ir_instruction *ir)
-{
-   ir_call *call = ir->as_call();
-
-   if (call && can_inline(call))
-      return true;
-
-   return false;
-}
-
 bool
 do_function_inlining(exec_list *instructions)
 {
    ir_function_inlining_visitor v;
 
-   do_expression_flattening(instructions, automatic_inlining_predicate);
-
    v.run(instructions);
 
    return v.progress;
@@ -89,12 +75,12 @@ static void
 replace_return_with_assignment(ir_instruction *ir, void *data)
 {
    void *ctx = ralloc_parent(ir);
-   ir_variable *retval = (ir_variable *)data;
+   ir_dereference *orig_deref = (ir_dereference *) data;
    ir_return *ret = ir->as_return();
 
    if (ret) {
       if (ret->value) {
-        ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
+        ir_rvalue *lhs = orig_deref->clone(ctx, NULL);
         ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
       } else {
         /* un-valued return has to be the last return, or we shouldn't
@@ -106,14 +92,13 @@ replace_return_with_assignment(ir_instruction *ir, void *data)
    }
 }
 
-ir_rvalue *
+void
 ir_call::generate_inline(ir_instruction *next_ir)
 {
    void *ctx = ralloc_parent(this);
    ir_variable **parameters;
    int num_parameters;
    int i;
-   ir_variable *retval = NULL;
    struct hash_table *ht;
 
    ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
@@ -124,13 +109,6 @@ ir_call::generate_inline(ir_instruction *next_ir)
 
    parameters = new ir_variable *[num_parameters];
 
-   /* Generate storage for the return value. */
-   if (!this->callee->return_type->is_void()) {
-      retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
-                                   ir_var_auto);
-      next_ir->insert_before(retval);
-   }
-
    /* Generate the declarations for the parameters to our inlined code,
     * and set up the mapping of real function body variables to ours.
     */
@@ -185,7 +163,7 @@ ir_call::generate_inline(ir_instruction *next_ir)
       ir_instruction *new_ir = ir->clone(ctx, ht);
 
       new_instructions.push_tail(new_ir);
-      visit_tree(new_ir, replace_return_with_assignment, retval);
+      visit_tree(new_ir, replace_return_with_assignment, this->return_deref);
    }
 
    /* If any samplers were passed in, replace any deref of the sampler
@@ -238,11 +216,6 @@ ir_call::generate_inline(ir_instruction *next_ir)
    delete [] parameters;
 
    hash_table_dtor(ht);
-
-   if (retval)
-      return new(ctx) ir_dereference_variable(retval);
-   else
-      return NULL;
 }
 
 
@@ -282,13 +255,7 @@ ir_visitor_status
 ir_function_inlining_visitor::visit_enter(ir_call *ir)
 {
    if (can_inline(ir)) {
-      /* If the call was part of some tree, then it should have been
-       * flattened out or we shouldn't have seen it because of a
-       * visit_continue_with_parent in this visitor.
-       */
-      assert(ir == base_ir);
-
-      (void) ir->generate_inline(ir);
+      ir->generate_inline(ir);
       ir->remove();
       this->progress = true;
    }
@@ -297,25 +264,6 @@ ir_function_inlining_visitor::visit_enter(ir_call *ir)
 }
 
 
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
-{
-   ir_call *call = ir->rhs->as_call();
-   if (!call || !can_inline(call))
-      return visit_continue;
-
-   /* generates the parameter setup, function body, and returns the return
-    * value of the function
-    */
-   ir_rvalue *rhs = call->generate_inline(ir);
-   assert(rhs);
-
-   ir->rhs = rhs;
-   this->progress = true;
-
-   return visit_continue;
-}
-
 /**
  * Replaces references to the "sampler" variable with a clone of "deref."
  *
index e2aff5f8071e721f1be9352161364cac36d963ae..e70a2240fca6ae98f2b06c8245e30dc4bd5a1715 100644 (file)
@@ -222,6 +222,9 @@ ir_tree_grafting_visitor::visit_enter(ir_call *ir)
       sig_iter.next();
    }
 
+   if (ir->return_deref && check_graft(ir, ir->return_deref->var) == visit_stop)
+      return visit_stop;
+
    return visit_continue;
 }