mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 17:30:12 +01:00
glsl2: Make sure functions end with a return before doing ir_if_return.
This catches a few remaining functions that weren't getting inlined, generally operating on global or out variables and using an early return to skip work when possible. Fixes for i965: glsl1-function with early return (3)
This commit is contained in:
parent
18964618a1
commit
a62ef12ef2
1 changed files with 61 additions and 1 deletions
|
|
@ -24,13 +24,16 @@
|
|||
/**
|
||||
* \file ir_if_return.cpp
|
||||
*
|
||||
* This pass tries to normalize functions to always return from one place.
|
||||
* This pass tries to normalize functions to always return from one
|
||||
* place by moving around blocks of code in if statements.
|
||||
*
|
||||
* This helps on hardware with no branching support, and may even be a
|
||||
* useful transform on hardware supporting control flow by turning
|
||||
* masked returns into normal returns.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "glsl_types.h"
|
||||
#include "ir.h"
|
||||
|
||||
class ir_if_return_visitor : public ir_hierarchical_visitor {
|
||||
|
|
@ -40,6 +43,7 @@ public:
|
|||
this->progress = false;
|
||||
}
|
||||
|
||||
ir_visitor_status visit_enter(ir_function_signature *);
|
||||
ir_visitor_status visit_enter(ir_if *);
|
||||
|
||||
void move_outer_block_inside(ir_instruction *ir,
|
||||
|
|
@ -138,6 +142,62 @@ ir_if_return_visitor::move_outer_block_inside(ir_instruction *ir,
|
|||
}
|
||||
}
|
||||
|
||||
/* Normalize a function to always have a return statement at the end.
|
||||
*
|
||||
* This avoids the ir_if handler needing to know whether it is at the
|
||||
* top level of the function to know if there's an implicit return at
|
||||
* the end of the outer block.
|
||||
*/
|
||||
ir_visitor_status
|
||||
ir_if_return_visitor::visit_enter(ir_function_signature *ir)
|
||||
{
|
||||
ir_return *ret;
|
||||
|
||||
if (!ir->is_defined)
|
||||
return visit_continue_with_parent;
|
||||
if (strcmp(ir->function_name(), "main") == 0)
|
||||
return visit_continue_with_parent;
|
||||
|
||||
ret = find_return_in_block(&ir->body);
|
||||
|
||||
if (ret) {
|
||||
truncate_after_instruction(ret);
|
||||
} else {
|
||||
if (ir->return_type->is_void()) {
|
||||
ir->body.push_tail(new(ir) ir_return(NULL));
|
||||
} else {
|
||||
/* Probably, if we've got a function with a return value
|
||||
* hitting this point, it's something like:
|
||||
*
|
||||
* float reduce_below_half(float val)
|
||||
* {
|
||||
* while () {
|
||||
* if (val >= 0.5)
|
||||
* val /= 2.0;
|
||||
* else
|
||||
* return val;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* So we gain a junk return statement of an undefined value
|
||||
* at the end that never gets executed. However, a backend
|
||||
* using this pass is probably desperate to get rid of
|
||||
* function calls, so go ahead and do it for their sake in
|
||||
* case it fixes apps.
|
||||
*/
|
||||
ir_variable *undef = new(ir) ir_variable(ir->return_type,
|
||||
"if_return_undef",
|
||||
ir_var_temporary);
|
||||
ir->body.push_tail(undef);
|
||||
|
||||
ir_dereference_variable *deref = new(ir) ir_dereference_variable(undef);
|
||||
ir->body.push_tail(new(ir) ir_return(deref));
|
||||
}
|
||||
}
|
||||
|
||||
return visit_continue;
|
||||
}
|
||||
|
||||
ir_visitor_status
|
||||
ir_if_return_visitor::visit_enter(ir_if *ir)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue