1 /*
2 * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Vadim Girlin
25 */
26
27 #include "sb_shader.h"
28 #include "sb_pass.h"
29
30 namespace r600_sb {
31
run()32 int ra_checker::run() {
33
34 rm_stack.clear();
35 rm_stack.resize(1);
36 rm_stk_level = 0;
37
38 process_op_dst(sh.root);
39
40 run_on(sh.root);
41
42 assert(rm_stk_level == 0);
43
44 dump_all_errors();
45
46 assert(sh.errors.empty());
47
48 return 0;
49 }
50
dump_error(const error_info & e)51 void ra_checker::dump_error(const error_info &e) {
52
53 sblog << "error at : ";
54 dump::dump_op(e.n);
55
56 sblog << "\n";
57 sblog << " : " << e.message << "\n";
58 }
59
dump_all_errors()60 void ra_checker::dump_all_errors() {
61 for (error_map::iterator I = sh.errors.begin(), E = sh.errors.end();
62 I != E; ++I) {
63 dump_error(I->second);
64 }
65 }
66
67
error(node * n,unsigned id,std::string msg)68 void ra_checker::error(node *n, unsigned id, std::string msg) {
69 error_info e;
70 e.n = n;
71 e.arg_index = id;
72 e.message = msg;
73 sh.errors.insert(std::make_pair(n, e));
74 }
75
push_stack()76 void ra_checker::push_stack() {
77 ++rm_stk_level;
78 if (rm_stack.size() == rm_stk_level)
79 rm_stack.push_back(rm_stack.back());
80 else
81 rm_stack[rm_stk_level] = rm_stack[rm_stk_level - 1];
82 }
83
pop_stack()84 void ra_checker::pop_stack() {
85 --rm_stk_level;
86 }
87
kill_alu_only_regs()88 void ra_checker::kill_alu_only_regs() {
89 // TODO
90 }
91
check_value_gpr(node * n,unsigned id,value * v)92 void ra_checker::check_value_gpr(node *n, unsigned id, value *v) {
93 sel_chan gpr = v->gpr;
94 if (!gpr) {
95 sb_ostringstream o;
96 o << "operand value " << *v << " is not allocated";
97 error(n, id, o.str());
98 return;
99 }
100 reg_value_map::iterator F = rmap().find(v->gpr);
101 if (F == rmap().end()) {
102 sb_ostringstream o;
103 o << "operand value " << *v << " was not previously written to its gpr";
104 error(n, id, o.str());
105 return;
106 }
107 if (!F->second->v_equal(v)) {
108 sb_ostringstream o;
109 o << "expected operand value " << *v
110 << ", gpr contains " << *(F->second);
111 error(n, id, o.str());
112 return;
113 }
114
115
116 }
117
check_src_vec(node * n,unsigned id,vvec & vv,bool src)118 void ra_checker::check_src_vec(node *n, unsigned id, vvec &vv, bool src) {
119
120 for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
121 value *v = *I;
122 if (!v || !v->is_sgpr())
123 continue;
124
125 if (v->is_rel()) {
126 if (!v->rel) {
127 sb_ostringstream o;
128 o << "expected relative offset in " << *v;
129 error(n, id, o.str());
130 return;
131 }
132 } else if (src) {
133 check_value_gpr(n, id, v);
134 }
135 }
136 }
137
check_op_src(node * n)138 void ra_checker::check_op_src(node *n) {
139 check_src_vec(n, 0, n->dst, false);
140 check_src_vec(n, 100, n->src, true);
141 }
142
process_op_dst(node * n)143 void ra_checker::process_op_dst(node *n) {
144
145 unsigned id = 0;
146
147 for (vvec::iterator I = n->dst.begin(), E = n->dst.end(); I != E; ++I) {
148 value *v = *I;
149
150 ++id;
151
152 if (!v)
153 continue;
154
155 if (v->is_sgpr()) {
156
157 if (!v->gpr) {
158 sb_ostringstream o;
159 o << "destination operand " << *v << " is not allocated";
160 error(n, id, o.str());
161 return;
162 }
163
164 rmap()[v->gpr] = v;
165 } else if (v->is_rel()) {
166 if (v->rel->is_const()) {
167 rmap()[v->get_final_gpr()] = v;
168 } else {
169 unsigned sz = v->array->array_size;
170 unsigned start = v->array->gpr;
171 for (unsigned i = 0; i < sz; ++i) {
172 rmap()[start + (i << 2)] = v;
173 }
174 }
175 }
176 }
177 }
178
check_phi_src(container_node * p,unsigned id)179 void ra_checker::check_phi_src(container_node *p, unsigned id) {
180 for (node_iterator I = p->begin(), E = p->end(); I != E; ++I) {
181 node *n = *I;
182 value *s = n->src[id];
183 if (s->is_sgpr())
184 check_value_gpr(n, id, s);
185 }
186 }
187
process_phi_dst(container_node * p)188 void ra_checker::process_phi_dst(container_node *p) {
189 for (node_iterator I = p->begin(), E = p->end(); I != E; ++I) {
190 node *n = *I;
191 process_op_dst(n);
192 }
193 }
194
check_alu_group(alu_group_node * g)195 void ra_checker::check_alu_group(alu_group_node *g) {
196
197 for (node_iterator I = g->begin(), E = g->end(); I != E; ++I) {
198 node *a = *I;
199 if (!a->is_alu_inst()) {
200 sb_ostringstream o;
201 o << "non-alu node inside alu group";
202 error(a, 0, o.str());
203 return;
204 }
205
206 check_op_src(a);
207 }
208
209 std::fill(prev_dst, prev_dst + 5, (value*)NULL);
210
211 for (node_iterator I = g->begin(), E = g->end(); I != E; ++I) {
212 alu_node *a = static_cast<alu_node*>(*I);
213
214 process_op_dst(a);
215
216 unsigned slot = a->bc.slot;
217 prev_dst[slot] = a->dst[0];
218 }
219 }
220
run_on(container_node * c)221 void ra_checker::run_on(container_node* c) {
222
223 if (c->is_region()) {
224 region_node *r = static_cast<region_node*>(c);
225 if (r->loop_phi) {
226 check_phi_src(r->loop_phi, 0);
227 process_phi_dst(r->loop_phi);
228 }
229 } else if (c->is_depart()) {
230
231 push_stack();
232
233 } else if (c->is_repeat()) {
234
235 push_stack();
236
237 }
238
239 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
240 node *n = *I;
241
242 if(n->is_cf_inst() || n->is_fetch_inst()) {
243 check_op_src(n);
244 process_op_dst(n);
245 }
246
247 if (n->is_container()) {
248 if (n->is_alu_group()) {
249 check_alu_group(static_cast<alu_group_node*>(n));
250 } else {
251 container_node *nc = static_cast<container_node*>(n);
252 run_on(nc);
253 }
254 }
255 }
256
257 if (c->is_depart()) {
258 depart_node *r = static_cast<depart_node*>(c);
259 check_phi_src(r->target->phi, r->dep_id);
260 pop_stack();
261 } else if (c->is_repeat()) {
262 repeat_node *r = static_cast<repeat_node*>(c);
263 assert (r->target->loop_phi);
264
265 pop_stack();
266 } else if (c->is_region()) {
267 region_node *r = static_cast<region_node*>(c);
268 if (r->phi)
269 process_phi_dst(r->phi);
270 }
271 }
272
273 } // namespace r600_sb
274