glsl: Convert ir_call to be a statement rather than a value.
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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user