Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Copyright © 2010 Intel Corporation
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 * copy of this software and associated documentation files (the "Software"),
6
 * to deal in the Software without restriction, including without limitation
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 * and/or sell copies of the Software, and to permit persons to whom the
9
 * Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice (including the next
12
 * paragraph) shall be included in all copies or substantial portions of the
13
 * Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 */
23
 
24
/**
25
 * \file opt_constant_variable.cpp
26
 *
27
 * Marks variables assigned a single constant value over the course
28
 * of the program as constant.
29
 *
30
 * The goal here is to trigger further constant folding and then dead
31
 * code elimination.  This is common with vector/matrix constructors
32
 * and calls to builtin functions.
33
 */
34
 
35
#include "ir.h"
36
#include "ir_visitor.h"
37
#include "ir_optimization.h"
38
#include "glsl_types.h"
39
 
40
struct assignment_entry {
41
   exec_node link;
42
   int assignment_count;
43
   ir_variable *var;
44
   ir_constant *constval;
45
   bool our_scope;
46
};
47
 
48
class ir_constant_variable_visitor : public ir_hierarchical_visitor {
49
public:
50
   virtual ir_visitor_status visit_enter(ir_dereference_variable *);
51
   virtual ir_visitor_status visit(ir_variable *);
52
   virtual ir_visitor_status visit_enter(ir_assignment *);
53
   virtual ir_visitor_status visit_enter(ir_call *);
54
 
55
   exec_list list;
56
};
57
 
58
static struct assignment_entry *
59
get_assignment_entry(ir_variable *var, exec_list *list)
60
{
61
   struct assignment_entry *entry;
62
 
63
   foreach_list_typed(struct assignment_entry, entry, link, list) {
64
      if (entry->var == var)
65
	 return entry;
66
   }
67
 
68
   entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
69
   entry->var = var;
70
   list->push_head(&entry->link);
71
   return entry;
72
}
73
 
74
ir_visitor_status
75
ir_constant_variable_visitor::visit(ir_variable *ir)
76
{
77
   struct assignment_entry *entry = get_assignment_entry(ir, &this->list);
78
   entry->our_scope = true;
79
   return visit_continue;
80
}
81
 
82
/* Skip derefs of variables so that we can detect declarations. */
83
ir_visitor_status
84
ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir)
85
{
86
   (void)ir;
87
   return visit_continue_with_parent;
88
}
89
 
90
ir_visitor_status
91
ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
92
{
93
   ir_constant *constval;
94
   struct assignment_entry *entry;
95
 
96
   entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list);
97
   assert(entry);
98
   entry->assignment_count++;
99
 
100
   /* If it's already constant, don't do the work. */
101
   if (entry->var->constant_value)
102
      return visit_continue;
103
 
104
   /* OK, now find if we actually have all the right conditions for
105
    * this to be a constant value assigned to the var.
106
    */
107
   if (ir->condition) {
108
      constval = ir->condition->constant_expression_value();
109
      if (!constval || !constval->value.b[0])
110
	 return visit_continue;
111
   }
112
 
113
   ir_variable *var = ir->whole_variable_written();
114
   if (!var)
115
      return visit_continue;
116
 
117
   constval = ir->rhs->constant_expression_value();
118
   if (!constval)
119
      return visit_continue;
120
 
121
   /* Mark this entry as having a constant assignment (if the
122
    * assignment count doesn't go >1).  do_constant_variable will fix
123
    * up the variable with the constant value later.
124
    */
125
   entry->constval = constval;
126
 
127
   return visit_continue;
128
}
129
 
130
ir_visitor_status
131
ir_constant_variable_visitor::visit_enter(ir_call *ir)
132
{
133
   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
134
   foreach_iter(exec_list_iterator, iter, *ir) {
135
      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
136
      ir_variable *param = (ir_variable *)sig_iter.get();
137
 
138
      if (param->mode == ir_var_out ||
139
	  param->mode == ir_var_inout) {
140
	 ir_variable *var = param_rval->variable_referenced();
141
	 struct assignment_entry *entry;
142
 
143
	 assert(var);
144
	 entry = get_assignment_entry(var, &this->list);
145
	 entry->assignment_count++;
146
      }
147
      sig_iter.next();
148
   }
149
   return visit_continue;
150
}
151
 
152
/**
153
 * Does a copy propagation pass on the code present in the instruction stream.
154
 */
155
bool
156
do_constant_variable(exec_list *instructions)
157
{
158
   bool progress = false;
159
   ir_constant_variable_visitor v;
160
 
161
   v.run(instructions);
162
 
163
   while (!v.list.is_empty()) {
164
 
165
      struct assignment_entry *entry;
166
      entry = exec_node_data(struct assignment_entry, v.list.head, link);
167
 
168
      if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
169
	 entry->var->constant_value = entry->constval;
170
	 progress = true;
171
      }
172
      entry->link.remove();
173
      free(entry);
174
   }
175
 
176
   return progress;
177
}
178
 
179
bool
180
do_constant_variable_unlinked(exec_list *instructions)
181
{
182
   bool progress = false;
183
 
184
   foreach_iter(exec_list_iterator, iter, *instructions) {
185
      ir_instruction *ir = (ir_instruction *)iter.get();
186
      ir_function *f = ir->as_function();
187
      if (f) {
188
	 foreach_iter(exec_list_iterator, sigiter, *f) {
189
	    ir_function_signature *sig =
190
	       (ir_function_signature *) sigiter.get();
191
	    if (do_constant_variable(&sig->body))
192
	       progress = true;
193
	 }
194
      }
195
   }
196
 
197
   return progress;
198
}