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