Home | History | Annotate | Download | only in sb
      1 /*
      2  * Copyright 2013 Vadim Girlin <vadimgirlin (at) 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 
     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 
     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 
     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 
     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 
     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 
     84 void ra_checker::pop_stack() {
     85 	--rm_stk_level;
     86 }
     87 
     88 void ra_checker::kill_alu_only_regs() {
     89 	// TODO
     90 }
     91 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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