[Mesa-dev] [PATCH 3/5] glsl: Convert ir_call to be a statement rather than an rvalue.

Ian Romanick idr at freedesktop.org
Wed Sep 21 18:44:07 PDT 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 09/20/2011 06:28 PM, Kenneth Graunke wrote:
| This begins the process of cleaning up and un-muddling our IR.
|
| 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.

It seems like a lot of the complexity in this patch (and the review
comments) comes from having to duplicate ir_assignment code.  I
haven't thought it through, but, is there a way to make an
ir_call_assignment that shares a common parent with ir_assignment.
This would necessitate an ir_call (without assignment), and that might
make things worse.  Thoughts?

| All expression trees are now pure, without exception.
|
| Signed-off-by: Kenneth Graunke<kenneth at whitecape.org> ---
| src/glsl/ast_function.cpp             |   49 ++++++++------------
| src/glsl/builtins/ir/acos             |   23 ++++++---
| src/glsl/builtins/ir/atan             |   80
| ++++++++++++++++++--------------- src/glsl/ir.cpp
| |    2 - src/glsl/ir.h                         |   21 ++++++---
| src/glsl/ir_basic_block.cpp           |   46 +------------------
| src/glsl/ir_clone.cpp                 |    6 ++-
| src/glsl/ir_constant_expression.cpp   |    3 -
| src/glsl/ir_expression_flattening.cpp |    6 +--
| src/glsl/ir_hv_accept.cpp             |    6 +++
| src/glsl/ir_print_visitor.cpp         |    5 ++-
| src/glsl/ir_reader.cpp                |   32 ++++++++++---
| src/glsl/ir_validate.cpp              |   12 +++++
| src/glsl/linker.cpp                   |    1 +
| src/glsl/opt_constant_folding.cpp     |   10 ++++
| src/glsl/opt_constant_variable.cpp    |   12 +++++
| src/glsl/opt_dead_code.cpp            |    3 +-
| src/glsl/opt_dead_code_local.cpp      |    7 +---
| src/glsl/opt_function_inlining.cpp    |   62
| ++----------------------- 19 files changed, 179 insertions(+), 207
| deletions(-)
|
| diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
| index 392b7f9..c7d9c06 100644 --- a/src/glsl/ast_function.cpp +++
| b/src/glsl/ast_function.cpp @@ -258,31 +258,24 @@
| match_function_by_name(exec_list *instructions, const char *name,
| 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 the instructions to call it;
| just generate an +       * ir_constant representing the constant
| value. * -       * Also insert any out parameter conversions after
| the call. +       * Function calls can only be constant expressions
| starting +       * 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, ralloc_asprintf(ctx, "%s_retval",
| sig->function_name()), @@ -290,16 +283,14 @@
| match_function_by_name(exec_list *instructions, const char *name,
| 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); - -	 deref = new(ctx)
| ir_dereference_variable(var); -      } else { -
| instructions->push_tail(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; }
| else { char *str = prototype_string(NULL, name,
| actual_parameters);
|
| diff --git a/src/glsl/builtins/ir/acos b/src/glsl/builtins/ir/acos
| index d1cfebe..f0078f8 100644 --- a/src/glsl/builtins/ir/acos +++
| b/src/glsl/builtins/ir/acos @@ -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))))) )) diff --git
| a/src/glsl/builtins/ir/atan b/src/glsl/builtins/ir/atan index
| 7b5ea13..a9dc08e 100644 --- a/src/glsl/builtins/ir/atan +++
| b/src/glsl/builtins/ir/atan @@ -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))))) @@ -82,12 +94,11
| @@ (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 @@ -95,15 +106,13 @@ (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 @@ -111,18 +120,15 @@ (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))))
|
| )) diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index
| 70d0ae2..92a7601 100644 --- a/src/glsl/ir.cpp +++
| b/src/glsl/ir.cpp @@ -1458,8 +1458,6 @@
| ir_function::has_user_signature() void
| ir_call::set_callee(ir_function_signature *sig) { -
| assert((this->type == NULL) || (this->type == sig->return_type));
| - this->callee = sig; }
|
| diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 9bf3b70..11deaf6
| 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -978,16 +978,17
| @@ 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
| *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;
| } @@ -1039,9 +1040,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 should be NULL if the
| return type is void. +    */ +   ir_dereference *return_deref;
|
| /* List of ir_rvalue of paramaters passed in this call. */
| exec_list actual_parameters; diff --git
| a/src/glsl/ir_basic_block.cpp b/src/glsl/ir_basic_block.cpp index
| a833825..5ebbf6f 100644 --- a/src/glsl/ir_basic_block.cpp +++
| b/src/glsl/ir_basic_block.cpp @@ -32,31 +32,6 @@ #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,9 @@ 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; -	 } +      } else if (ir->as_call()) { +
| callback(leader, ir, data); +	 leader = NULL; } last = ir; } diff
| --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index
| e8b946a..3993ff3 100644 --- a/src/glsl/ir_clone.cpp +++
| b/src/glsl/ir_clone.cpp @@ -156,6 +156,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 *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) {
| @@ -163,7 +167,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 * diff --git a/src/glsl/ir_constant_expression.cpp
| b/src/glsl/ir_constant_expression.cpp index 4264847..bc0b589
| 100644 --- a/src/glsl/ir_constant_expression.cpp +++
| b/src/glsl/ir_constant_expression.cpp @@ -983,9 +983,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);
| }
|
| diff --git a/src/glsl/ir_expression_flattening.cpp
| b/src/glsl/ir_expression_flattening.cpp index 0b7c537..3922da8
| 100644 --- a/src/glsl/ir_expression_flattening.cpp +++
| b/src/glsl/ir_expression_flattening.cpp @@ -27,10 +27,8 @@ * Takes
| the leaves of expression trees and makes them dereferences of *
| assignments of the leaves to temporaries, according to a
| predicate. * - * This is 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. + * This is
| used for breaking down matrix operations, where it's easier to + *
| create a temporary and work on each of its vectory components
| individually. */
|
| #include "ir.h" diff --git a/src/glsl/ir_hv_accept.cpp
| b/src/glsl/ir_hv_accept.cpp index d33fc85..f8cd776 100644 ---
| a/src/glsl/ir_hv_accept.cpp +++ b/src/glsl/ir_hv_accept.cpp @@
| -317,6 +317,12 @@ 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) { +      s =
| this->return_deref->accept(v); +      if (s != visit_continue) +
| return (s == visit_continue_with_parent) ? visit_continue : s; +
| } + s = visit_list_elements(v,&this->actual_parameters); if (s ==
| visit_stop) return s; diff --git a/src/glsl/ir_print_visitor.cpp
| b/src/glsl/ir_print_visitor.cpp index ea78582..b0a9c58 100644 ---
| a/src/glsl/ir_print_visitor.cpp +++
| b/src/glsl/ir_print_visitor.cpp @@ -409,7 +409,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();
|
| diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp index
| 2d0bccb..bd341fe 100644 --- a/src/glsl/ir_reader.cpp +++
| b/src/glsl/ir_reader.cpp @@ -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 *); @@ -347,6 +347,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) { @@ -520,8 +522,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 { @@ -609,10 +609,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 *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_dereference(s_return); +      if (return_deref == NULL) { +
| ir_read_error(s_return, "when reading return deref of call"); +
| return NULL; +      } +   } else if (!MATCH(expr, void_pat)) { +
| ir_read_error(expr, "expected (call<name>  [<deref>] (<param>
| ...))"); return NULL; }
|
| @@ -642,7 +652,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 * diff --git a/src/glsl/ir_validate.cpp
| b/src/glsl/ir_validate.cpp index 2d1c609..848305c 100644 ---
| a/src/glsl/ir_validate.cpp +++ b/src/glsl/ir_validate.cpp @@ -537,6
| +537,18 @@ ir_validate::visit_enter(ir_call *ir) {
| ir_function_signature *const callee = ir->get_callee();
|
| +   if (callee->return_type != glsl_type::void_type) { +      if
| (ir->return_deref == NULL) { +	 printf("ir_call has non-void callee
| but no return storage\n"); +	 abort(); +      } +      if
| (callee->return_type != ir->return_deref->type) { +	 printf("callee
| type %s does not match return storage type %s\n", +
| callee->return_type->name, ir->return_deref->type->name); +
| abort(); +      } +   } + if (callee->ir_type !=
| ir_type_function_signature) { printf("IR called by ir_call is not
| ir_function_signature!\n"); abort(); diff --git
| a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 195f58f..1606a67
| 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@
| -754,6 +754,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) { diff --git a/src/glsl/opt_constant_folding.cpp
| b/src/glsl/opt_constant_folding.cpp index 599b215..db8cd5c 100644
| --- a/src/glsl/opt_constant_folding.cpp +++
| b/src/glsl/opt_constant_folding.cpp @@ -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; }
|
| diff --git a/src/glsl/opt_constant_variable.cpp
| b/src/glsl/opt_constant_variable.cpp index 3fa7c3b..18c2801 100644
| --- a/src/glsl/opt_constant_variable.cpp +++
| b/src/glsl/opt_constant_variable.cpp @@ -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; }
|
| diff --git a/src/glsl/opt_dead_code.cpp
| b/src/glsl/opt_dead_code.cpp index cb500d2..35609e9 100644 ---
| a/src/glsl/opt_dead_code.cpp +++ b/src/glsl/opt_dead_code.cpp @@
| -78,8 +78,7 @@ do_dead_code(exec_list *instructions) * 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;
|
| diff --git a/src/glsl/opt_dead_code_local.cpp
| b/src/glsl/opt_dead_code_local.cpp index 39962bd..a81a38f 100644
| --- a/src/glsl/opt_dead_code_local.cpp +++
| b/src/glsl/opt_dead_code_local.cpp @@ -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);
|
| diff --git a/src/glsl/opt_function_inlining.cpp
| b/src/glsl/opt_function_inlining.cpp index 8fef358..4138dbe 100644
| --- a/src/glsl/opt_function_inlining.cpp +++
| b/src/glsl/opt_function_inlining.cpp @@ -54,7 +54,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 *); @@ -64,23 +63,10 @@
| 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; @@ -90,12 +76,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 @@ -107,14 +93,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); @@ -125,13 +110,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. */
| @@ -186,7 +164,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 @@ -239,11 +217,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; }
|
|
| @@ -283,13 +256,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; } @@ -298,25 +265,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." *

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iEYEARECAAYFAk56kucACgkQX1gOwKyEAw9n+wCglgNUeiQpMDWIjCW0qEqQbden
+RYAnjhK2Dp1ESGRh4zQCQXdCYCd6f6d
=Pd5S
-----END PGP SIGNATURE-----


More information about the mesa-dev mailing list