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