• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- c++ -*- */
2 /*
3  * Copyright © 2010 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #pragma once
26 #ifndef LOOP_ANALYSIS_H
27 #define LOOP_ANALYSIS_H
28 
29 #include "ir.h"
30 #include "util/hash_table.h"
31 
32 /**
33  * Analyze and classify all variables used in all loops in the instruction list
34  */
35 extern class loop_state *
36 analyze_loop_variables(exec_list *instructions);
37 
38 
39 /**
40  * Fill in loop control fields
41  *
42  * Based on analysis of loop variables, this function tries to remove
43  * redundant sequences in the loop of the form
44  *
45  *  (if (expression bool ...) (break))
46  *
47  * For example, if it is provable that one loop exit condition will
48  * always be satisfied before another, the unnecessary exit condition will be
49  * removed.
50  */
51 extern bool
52 set_loop_controls(exec_list *instructions, loop_state *ls);
53 
54 
55 extern bool
56 unroll_loops(exec_list *instructions, loop_state *ls,
57              const struct gl_shader_compiler_options *options);
58 
59 ir_rvalue *
60 find_initial_value(ir_loop *loop, ir_variable *var);
61 
62 int
63 calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
64 		     enum ir_expression_operation op);
65 
66 
67 /**
68  * Tracking for all variables used in a loop
69  */
70 class loop_variable_state : public exec_node {
71 public:
72    class loop_variable *get(const ir_variable *);
73    class loop_variable *insert(ir_variable *);
74    class loop_variable *get_or_insert(ir_variable *, bool in_assignee);
75    class loop_terminator *insert(ir_if *);
76 
77 
78    /**
79     * Variables that have not yet been classified
80     */
81    exec_list variables;
82 
83    /**
84     * Variables whose values are constant within the body of the loop
85     *
86     * This list contains \c loop_variable objects.
87     */
88    exec_list constants;
89 
90    /**
91     * Induction variables for this loop
92     *
93     * This list contains \c loop_variable objects.
94     */
95    exec_list induction_variables;
96 
97    /**
98     * Simple if-statements that lead to the termination of the loop
99     *
100     * This list contains \c loop_terminator objects.
101     *
102     * \sa is_loop_terminator
103     */
104    exec_list terminators;
105 
106    /**
107     * If any of the terminators in \c terminators leads to termination of the
108     * loop after a constant number of iterations, this is the terminator that
109     * leads to termination after the smallest number of iterations.  Otherwise
110     * NULL.
111     */
112    loop_terminator *limiting_terminator;
113 
114    /**
115     * Hash table containing all variables accessed in this loop
116     */
117    hash_table *var_hash;
118 
119    /**
120     * Number of ir_loop_jump instructions that operate on this loop
121     */
122    unsigned num_loop_jumps;
123 
124    /**
125     * Whether this loop contains any function calls.
126     */
127    bool contains_calls;
128 
loop_variable_state()129    loop_variable_state()
130    {
131       this->num_loop_jumps = 0;
132       this->contains_calls = false;
133       this->var_hash = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
134                                                _mesa_key_pointer_equal);
135       this->limiting_terminator = NULL;
136    }
137 
~loop_variable_state()138    ~loop_variable_state()
139    {
140       _mesa_hash_table_destroy(this->var_hash, NULL);
141    }
142 
143    DECLARE_RALLOC_CXX_OPERATORS(loop_variable_state)
144 };
145 
146 
147 class loop_variable : public exec_node {
148 public:
149    /** The variable in question. */
150    ir_variable *var;
151 
152    /** Is the variable read in the loop before it is written? */
153    bool read_before_write;
154 
155    /** Are all variables in the RHS of the assignment loop constants? */
156    bool rhs_clean;
157 
158    /**
159     * Is there an assignment to the variable that is conditional, or inside a
160     * nested loop?
161     */
162    bool conditional_or_nested_assignment;
163 
164    /** Reference to the first assignment to the variable in the loop body. */
165    ir_assignment *first_assignment;
166 
167    /** Number of assignments to the variable in the loop body. */
168    unsigned num_assignments;
169 
170    /**
171     * Increment value for a loop induction variable
172     *
173     * If this is a loop induction variable, the amount by which the variable
174     * is incremented on each iteration through the loop.
175     *
176     * If this is not a loop induction variable, NULL.
177     */
178    ir_rvalue *increment;
179 
180 
is_induction_var()181    inline bool is_induction_var() const
182    {
183       /* Induction variables always have a non-null increment, and vice
184        * versa.
185        */
186       return this->increment != NULL;
187    }
188 
189 
is_loop_constant()190    inline bool is_loop_constant() const
191    {
192       const bool is_const = (this->num_assignments == 0)
193          || (((this->num_assignments == 1)
194 	     && !this->conditional_or_nested_assignment
195 	     && !this->read_before_write
196              && this->rhs_clean) || this->var->data.read_only);
197 
198       /* If the RHS of *the* assignment is clean, then there must be exactly
199        * one assignment of the variable.
200        */
201       assert((this->rhs_clean && (this->num_assignments == 1))
202 	     || !this->rhs_clean);
203 
204       return is_const;
205    }
206 
207    void record_reference(bool in_assignee,
208                          bool in_conditional_code_or_nested_loop,
209                          ir_assignment *current_assignment);
210 };
211 
212 
213 class loop_terminator : public exec_node {
214 public:
loop_terminator()215    loop_terminator()
216       : ir(NULL), iterations(-1)
217    {
218    }
219 
220    /**
221     * Statement which terminates the loop.
222     */
223    ir_if *ir;
224 
225    /**
226     * The number of iterations after which the terminator is known to
227     * terminate the loop (if that is a fixed value).  Otherwise -1.
228     */
229    int iterations;
230 };
231 
232 
233 class loop_state {
234 public:
235    ~loop_state();
236 
237    /**
238     * Get the loop variable state data for a particular loop
239     */
240    loop_variable_state *get(const ir_loop *);
241 
242    loop_variable_state *insert(ir_loop *ir);
243 
244    bool loop_found;
245 
246 private:
247    loop_state();
248 
249    /**
250     * Hash table containing all loops that have been analyzed.
251     */
252    hash_table *ht;
253 
254    void *mem_ctx;
255 
256    friend loop_state *analyze_loop_variables(exec_list *instructions);
257 };
258 
259 #endif /* LOOP_ANALYSIS_H */
260