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