-----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<kenn...@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----- _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev