101e04c3fSmrg/* -*- c++ -*- */ 201e04c3fSmrg/* 301e04c3fSmrg * Copyright © 2010 Intel Corporation 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 601e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 701e04c3fSmrg * to deal in the Software without restriction, including without limitation 801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1101e04c3fSmrg * 1201e04c3fSmrg * The above copyright notice and this permission notice (including the next 1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1401e04c3fSmrg * Software. 1501e04c3fSmrg * 1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2201e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2301e04c3fSmrg */ 2401e04c3fSmrg 2501e04c3fSmrg#ifndef LOOP_ANALYSIS_H 2601e04c3fSmrg#define LOOP_ANALYSIS_H 2701e04c3fSmrg 2801e04c3fSmrg#include "ir.h" 2901e04c3fSmrg#include "util/hash_table.h" 3001e04c3fSmrg 3101e04c3fSmrg/** 3201e04c3fSmrg * Analyze and classify all variables used in all loops in the instruction list 3301e04c3fSmrg */ 3401e04c3fSmrgextern class loop_state * 3501e04c3fSmrganalyze_loop_variables(exec_list *instructions); 3601e04c3fSmrg 3701e04c3fSmrgstatic inline bool 3801e04c3fSmrgis_break(ir_instruction *ir) 3901e04c3fSmrg{ 4001e04c3fSmrg return ir != NULL && ir->ir_type == ir_type_loop_jump && 4101e04c3fSmrg ((ir_loop_jump *) ir)->is_break(); 4201e04c3fSmrg} 4301e04c3fSmrg 4401e04c3fSmrg 4501e04c3fSmrgextern bool 4601e04c3fSmrgunroll_loops(exec_list *instructions, loop_state *ls, 4701e04c3fSmrg const struct gl_shader_compiler_options *options); 4801e04c3fSmrg 4901e04c3fSmrg 5001e04c3fSmrg/** 5101e04c3fSmrg * Tracking for all variables used in a loop 5201e04c3fSmrg */ 5301e04c3fSmrgclass loop_variable_state : public exec_node { 5401e04c3fSmrgpublic: 5501e04c3fSmrg class loop_variable *get(const ir_variable *); 5601e04c3fSmrg class loop_variable *insert(ir_variable *); 5701e04c3fSmrg class loop_variable *get_or_insert(ir_variable *, bool in_assignee); 5801e04c3fSmrg class loop_terminator *insert(ir_if *, bool continue_from_then); 5901e04c3fSmrg 6001e04c3fSmrg 6101e04c3fSmrg /** 6201e04c3fSmrg * Variables that have not yet been classified 6301e04c3fSmrg */ 6401e04c3fSmrg exec_list variables; 6501e04c3fSmrg 6601e04c3fSmrg /** 6701e04c3fSmrg * Variables whose values are constant within the body of the loop 6801e04c3fSmrg * 6901e04c3fSmrg * This list contains \c loop_variable objects. 7001e04c3fSmrg */ 7101e04c3fSmrg exec_list constants; 7201e04c3fSmrg 7301e04c3fSmrg /** 7401e04c3fSmrg * Induction variables for this loop 7501e04c3fSmrg * 7601e04c3fSmrg * This list contains \c loop_variable objects. 7701e04c3fSmrg */ 7801e04c3fSmrg exec_list induction_variables; 7901e04c3fSmrg 8001e04c3fSmrg /** 8101e04c3fSmrg * Simple if-statements that lead to the termination of the loop 8201e04c3fSmrg * 8301e04c3fSmrg * This list contains \c loop_terminator objects. 8401e04c3fSmrg * 8501e04c3fSmrg * \sa is_loop_terminator 8601e04c3fSmrg */ 8701e04c3fSmrg exec_list terminators; 8801e04c3fSmrg 8901e04c3fSmrg /** 9001e04c3fSmrg * If any of the terminators in \c terminators leads to termination of the 9101e04c3fSmrg * loop after a constant number of iterations, this is the terminator that 9201e04c3fSmrg * leads to termination after the smallest number of iterations. Otherwise 9301e04c3fSmrg * NULL. 9401e04c3fSmrg */ 9501e04c3fSmrg loop_terminator *limiting_terminator; 9601e04c3fSmrg 9701e04c3fSmrg /** 9801e04c3fSmrg * Hash table containing all variables accessed in this loop 9901e04c3fSmrg */ 10001e04c3fSmrg hash_table *var_hash; 10101e04c3fSmrg 10201e04c3fSmrg /** 10301e04c3fSmrg * Number of ir_loop_jump instructions that operate on this loop 10401e04c3fSmrg */ 10501e04c3fSmrg unsigned num_loop_jumps; 10601e04c3fSmrg 10701e04c3fSmrg /** 10801e04c3fSmrg * Whether this loop contains any function calls. 10901e04c3fSmrg */ 11001e04c3fSmrg bool contains_calls; 11101e04c3fSmrg 11201e04c3fSmrg loop_variable_state() 11301e04c3fSmrg { 11401e04c3fSmrg this->num_loop_jumps = 0; 11501e04c3fSmrg this->contains_calls = false; 1167e102996Smaya this->var_hash = _mesa_pointer_hash_table_create(NULL); 11701e04c3fSmrg this->limiting_terminator = NULL; 11801e04c3fSmrg } 11901e04c3fSmrg 12001e04c3fSmrg ~loop_variable_state() 12101e04c3fSmrg { 12201e04c3fSmrg _mesa_hash_table_destroy(this->var_hash, NULL); 12301e04c3fSmrg } 12401e04c3fSmrg 12501e04c3fSmrg DECLARE_RALLOC_CXX_OPERATORS(loop_variable_state) 12601e04c3fSmrg}; 12701e04c3fSmrg 12801e04c3fSmrg 12901e04c3fSmrgclass loop_variable : public exec_node { 13001e04c3fSmrgpublic: 13101e04c3fSmrg /** The variable in question. */ 13201e04c3fSmrg ir_variable *var; 13301e04c3fSmrg 13401e04c3fSmrg /** Is the variable read in the loop before it is written? */ 13501e04c3fSmrg bool read_before_write; 13601e04c3fSmrg 13701e04c3fSmrg /** Are all variables in the RHS of the assignment loop constants? */ 13801e04c3fSmrg bool rhs_clean; 13901e04c3fSmrg 14001e04c3fSmrg /** 14101e04c3fSmrg * Is there an assignment to the variable that is conditional, or inside a 14201e04c3fSmrg * nested loop? 14301e04c3fSmrg */ 14401e04c3fSmrg bool conditional_or_nested_assignment; 14501e04c3fSmrg 14601e04c3fSmrg /** Reference to the first assignment to the variable in the loop body. */ 14701e04c3fSmrg ir_assignment *first_assignment; 14801e04c3fSmrg 14901e04c3fSmrg /** Number of assignments to the variable in the loop body. */ 15001e04c3fSmrg unsigned num_assignments; 15101e04c3fSmrg 15201e04c3fSmrg /** 15301e04c3fSmrg * Increment value for a loop induction variable 15401e04c3fSmrg * 15501e04c3fSmrg * If this is a loop induction variable, the amount by which the variable 15601e04c3fSmrg * is incremented on each iteration through the loop. 15701e04c3fSmrg * 15801e04c3fSmrg * If this is not a loop induction variable, NULL. 15901e04c3fSmrg */ 16001e04c3fSmrg ir_rvalue *increment; 16101e04c3fSmrg 16201e04c3fSmrg 16301e04c3fSmrg inline bool is_induction_var() const 16401e04c3fSmrg { 16501e04c3fSmrg /* Induction variables always have a non-null increment, and vice 16601e04c3fSmrg * versa. 16701e04c3fSmrg */ 16801e04c3fSmrg return this->increment != NULL; 16901e04c3fSmrg } 17001e04c3fSmrg 17101e04c3fSmrg 17201e04c3fSmrg inline bool is_loop_constant() const 17301e04c3fSmrg { 17401e04c3fSmrg const bool is_const = (this->num_assignments == 0) 17501e04c3fSmrg || (((this->num_assignments == 1) 17601e04c3fSmrg && !this->conditional_or_nested_assignment 17701e04c3fSmrg && !this->read_before_write 17801e04c3fSmrg && this->rhs_clean) || this->var->data.read_only); 17901e04c3fSmrg 18001e04c3fSmrg /* If the RHS of *the* assignment is clean, then there must be exactly 18101e04c3fSmrg * one assignment of the variable. 18201e04c3fSmrg */ 18301e04c3fSmrg assert((this->rhs_clean && (this->num_assignments == 1)) 18401e04c3fSmrg || !this->rhs_clean); 18501e04c3fSmrg 18601e04c3fSmrg return is_const; 18701e04c3fSmrg } 18801e04c3fSmrg 18901e04c3fSmrg void record_reference(bool in_assignee, 19001e04c3fSmrg bool in_conditional_code_or_nested_loop, 19101e04c3fSmrg ir_assignment *current_assignment); 19201e04c3fSmrg}; 19301e04c3fSmrg 19401e04c3fSmrg 19501e04c3fSmrgclass loop_terminator : public exec_node { 19601e04c3fSmrgpublic: 1977ec681f3Smrg loop_terminator(ir_if *ir, bool continue_from_then) 1987ec681f3Smrg : ir(ir), iterations(-1), continue_from_then(continue_from_then) 19901e04c3fSmrg { 20001e04c3fSmrg } 20101e04c3fSmrg 20201e04c3fSmrg /** 20301e04c3fSmrg * Statement which terminates the loop. 20401e04c3fSmrg */ 20501e04c3fSmrg ir_if *ir; 20601e04c3fSmrg 20701e04c3fSmrg /** 20801e04c3fSmrg * The number of iterations after which the terminator is known to 20901e04c3fSmrg * terminate the loop (if that is a fixed value). Otherwise -1. 21001e04c3fSmrg */ 21101e04c3fSmrg int iterations; 21201e04c3fSmrg 21301e04c3fSmrg /* Does the if continue from the then branch or the else branch */ 21401e04c3fSmrg bool continue_from_then; 21501e04c3fSmrg}; 21601e04c3fSmrg 21701e04c3fSmrg 21801e04c3fSmrgclass loop_state { 21901e04c3fSmrgpublic: 22001e04c3fSmrg ~loop_state(); 22101e04c3fSmrg 22201e04c3fSmrg /** 22301e04c3fSmrg * Get the loop variable state data for a particular loop 22401e04c3fSmrg */ 22501e04c3fSmrg loop_variable_state *get(const ir_loop *); 22601e04c3fSmrg 22701e04c3fSmrg loop_variable_state *insert(ir_loop *ir); 22801e04c3fSmrg 22901e04c3fSmrg bool loop_found; 23001e04c3fSmrg 23101e04c3fSmrgprivate: 23201e04c3fSmrg loop_state(); 23301e04c3fSmrg 23401e04c3fSmrg /** 23501e04c3fSmrg * Hash table containing all loops that have been analyzed. 23601e04c3fSmrg */ 23701e04c3fSmrg hash_table *ht; 23801e04c3fSmrg 23901e04c3fSmrg void *mem_ctx; 24001e04c3fSmrg 24101e04c3fSmrg friend loop_state *analyze_loop_variables(exec_list *instructions); 24201e04c3fSmrg}; 24301e04c3fSmrg 24401e04c3fSmrg#endif /* LOOP_ANALYSIS_H */ 245