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