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 #define GVN_DEBUG 0
     28 
     29 #if GVN_DEBUG
     30 #define GVN_DUMP(q) do { q } while (0)
     31 #else
     32 #define GVN_DUMP(q)
     33 #endif
     34 
     35 #include "sb_shader.h"
     36 #include "sb_pass.h"
     37 #include "sb_sched.h"
     38 
     39 namespace r600_sb {
     40 
     41 bool gvn::visit(node& n, bool enter) {
     42 	if (enter) {
     43 
     44 
     45 		bool rewrite = true;
     46 
     47 		if (n.dst[0]->is_agpr()) {
     48 			rewrite = false;
     49 		}
     50 
     51 
     52 		process_op(n, rewrite);
     53 
     54 		assert(n.parent);
     55 
     56 		if (n.parent->subtype == NST_LOOP_PHI_CONTAINER) {
     57 			// There is a problem - sometimes with nested loops
     58 			// loop counter initialization for inner loop is incorrectly hoisted
     59 			// out of the outer loop
     60 
     61 			// FIXME not sure if this is enough to fix a problem completely,
     62 			// possibly more complete fix is needed (anyway, the
     63 			// problem was seen only in relatively complex
     64 			// case involving nested loops and
     65 			// indirect access to loop counters (without proper array info
     66 			// loop counters may be considered as array elements too),
     67 			// was not seen in any tests
     68 			// or real apps when proper array information is available in TGSI).
     69 
     70 			// For now just mark the instructions that initialize loop counters
     71 			// with DONT_HOIST flag to prevent the insts like MOV r, 0
     72 			// (initialization of inner loop's counter with const)
     73 			// from being hoisted out of the outer loop
     74 
     75 			assert(!n.src.empty());
     76 			value *v = n.src[0];
     77 
     78 			if (v->is_any_gpr() && v->def)
     79 				v->def->flags |= NF_DONT_HOIST;
     80 		}
     81 
     82 	} else {
     83 	}
     84 	return true;
     85 }
     86 
     87 bool gvn::visit(cf_node& n, bool enter) {
     88 	if (enter) {
     89 		process_op(n);
     90 	} else {
     91 	}
     92 	return true;
     93 }
     94 
     95 bool gvn::visit(alu_node& n, bool enter) {
     96 	if (enter) {
     97 		process_op(n);
     98 	} else {
     99 	}
    100 	return true;
    101 }
    102 
    103 bool gvn::visit(alu_packed_node& n, bool enter) {
    104 	if (enter) {
    105 		process_op(n);
    106 	} else {
    107 	}
    108 	return false;
    109 }
    110 
    111 bool gvn::visit(fetch_node& n, bool enter) {
    112 	if (enter) {
    113 		process_op(n);
    114 	} else {
    115 	}
    116 	return true;
    117 }
    118 
    119 bool gvn::visit(region_node& n, bool enter) {
    120 	if (enter) {
    121 // FIXME: loop_phi sources are undefined yet (except theone from the preceding
    122 // code), can we handle that somehow?
    123 //		if (n.loop_phi)
    124 //			run_on(*n.loop_phi);
    125 	} else {
    126 		if (n.loop_phi)
    127 			run_on(*n.loop_phi);
    128 
    129 		if (n.phi)
    130 			run_on(*n.phi);
    131 	}
    132 	return true;
    133 }
    134 
    135 bool gvn::process_src(value* &v, bool rewrite) {
    136 	if (!v->gvn_source)
    137 		sh.vt.add_value(v);
    138 
    139 	if (rewrite && !v->gvn_source->is_rel()) {
    140 		v = v->gvn_source;
    141 		return true;
    142 	}
    143 	return false;
    144 }
    145 
    146 // FIXME: maybe handle it in the scheduler?
    147 void gvn::process_alu_src_constants(node &n, value* &v) {
    148 	if (n.src.size() < 3) {
    149 		process_src(v, true);
    150 		return;
    151 	}
    152 
    153 	if (!v->gvn_source)
    154 		sh.vt.add_value(v);
    155 
    156 	rp_kcache_tracker kc(sh);
    157 
    158 	if (v->gvn_source->is_kcache())
    159 		kc.try_reserve(v->gvn_source->select);
    160 
    161 	// don't propagate 3rd constant to the trans-only instruction
    162 	if (!n.is_alu_packed()) {
    163 		alu_node *a = static_cast<alu_node*>(&n);
    164 		if (a->bc.op_ptr->src_count == 3 && !(a->bc.slot_flags & AF_V)) {
    165 			unsigned const_count = 0;
    166 			for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E;
    167 					++I) {
    168 				value *c = (*I);
    169 				if (c && c->is_readonly() && ++const_count == 2) {
    170 					process_src(v, false);
    171 					return;
    172 				}
    173 			}
    174 		}
    175 	}
    176 
    177 	for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) {
    178 		value *c = (*I);
    179 
    180 		if (c->is_kcache() && !kc.try_reserve(c->select)) {
    181 			process_src(v, false);
    182 			return;
    183 		}
    184 	}
    185 	process_src(v, true);
    186 }
    187 
    188 void gvn::process_op(node& n, bool rewrite) {
    189 
    190 	for(vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) {
    191 		value* &v = *I;
    192 		if (v) {
    193 			if (v->rel) {
    194 				process_src(v->rel, rewrite);
    195 			}
    196 
    197 			if (rewrite && v->gvn_source && v->gvn_source->is_readonly() &&
    198 					n.is_any_alu()) {
    199 				process_alu_src_constants(n, v);
    200 			} else if (rewrite && v->gvn_source && v->gvn_source->is_const() &&
    201 					(n.is_fetch_op(FETCH_OP_VFETCH) ||
    202 							n.is_fetch_op(FETCH_OP_SEMFETCH)))
    203 				process_src(v, false);
    204 			else
    205 				process_src(v, rewrite);
    206 		}
    207 	}
    208 	if (n.pred)
    209 		process_src(n.pred, false);
    210 
    211 	if (n.type == NT_IF) {
    212 		if_node &i = (if_node&)n;
    213 		if (i.cond)
    214 			process_src(i.cond, false);
    215 	}
    216 
    217 	for(vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) {
    218 		value *v = *I;
    219 		if (v) {
    220 			if (v->rel)
    221 				process_src(v->rel, rewrite);
    222 			sh.vt.add_value(v);
    223 		}
    224 	}
    225 }
    226 
    227 } // namespace r600_sb
    228