[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,¶meters); + 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,¶meters); }
|
| 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