2 * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
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:
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
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.
30 #define PPH_DUMP(q) do { q } while (0)
35 #include "sb_shader.h"
47 void peephole::run_on(container_node* c) {
49 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
52 if (n->is_container())
53 run_on(static_cast<container_node*>(n));
56 if (n->is_alu_inst()) {
57 alu_node *a = static_cast<alu_node*>(n);
59 if (a->bc.op_ptr->flags &
60 (AF_PRED | AF_SET | AF_CMOV | AF_KILL)) {
62 } else if (a->bc.op == ALU_OP1_FLT_TO_INT) {
65 if (get_bool_flt_to_int_source(s)) {
66 convert_float_setcc(a, s);
74 void peephole::optimize_cc_op(alu_node* a) {
75 unsigned aflags = a->bc.op_ptr->flags;
77 if (aflags & (AF_PRED | AF_SET | AF_KILL)) {
79 } else if (aflags & AF_CMOV) {
84 void peephole::convert_float_setcc(alu_node *f2i, alu_node *s) {
85 alu_node *ns = sh.clone(s);
87 ns->dst[0] = f2i->dst[0];
89 ns->bc.set_op(ns->bc.op + (ALU_OP2_SETE_DX10 - ALU_OP2_SETE));
90 f2i->insert_after(ns);
94 void peephole::optimize_cc_op2(alu_node* a) {
96 unsigned flags = a->bc.op_ptr->flags;
97 unsigned cc = flags & AF_CC_MASK;
99 if ((cc != AF_CC_E && cc != AF_CC_NE) || a->pred)
102 unsigned cmp_type = flags & AF_CMP_TYPE_MASK;
103 unsigned dst_type = flags & AF_DST_TYPE_MASK;
105 int op_kind = (flags & AF_PRED) ? 1 :
106 (flags & AF_SET) ? 2 :
107 (flags & AF_KILL) ? 3 : 0;
109 bool swapped = false;
111 if (a->src[0]->is_const() && a->src[0]->literal_value == literal(0)) {
112 std::swap(a->src[0],a->src[1]);
115 memset(&a->bc.src[0], 0, sizeof(bc_alu_src));
116 memset(&a->bc.src[1], 0, sizeof(bc_alu_src));
119 if (swapped || (a->src[1]->is_const() &&
120 a->src[1]->literal_value == literal(0))) {
122 value *s = a->src[0];
124 bool_op_info bop = {};
132 if (!get_bool_op_info(s, bop))
136 bop.invert = !bop.invert;
138 bool swap_args = false;
140 cc = bop.n->bc.op_ptr->flags & AF_CC_MASK;
143 cc = invert_setcc_condition(cc, swap_args);
146 assert(cmp_type != AF_FLOAT_CMP);
147 cmp_type = AF_FLOAT_CMP;
151 sblog << "boi node: ";
152 dump::dump_op(bop.n);
153 sblog << " invert: " << bop.invert << " int_cvt: " << bop.int_cvt;
161 newop = get_predsetcc_op(cc, cmp_type);
164 newop = get_setcc_op(cc, cmp_type, dst_type != AF_FLOAT_DST);
167 newop = get_killcc_op(cc, cmp_type);
171 assert(!"invalid op kind");
178 a->src[0] = bop.n->src[1];
179 a->src[1] = bop.n->src[0];
180 a->bc.src[0] = bop.n->bc.src[1];
181 a->bc.src[1] = bop.n->bc.src[0];
184 a->src[0] = bop.n->src[0];
185 a->src[1] = bop.n->src[1];
186 a->bc.src[0] = bop.n->bc.src[0];
187 a->bc.src[1] = bop.n->bc.src[1];
192 void peephole::optimize_CNDcc_op(alu_node* a) {
193 unsigned flags = a->bc.op_ptr->flags;
194 unsigned cc = flags & AF_CC_MASK;
195 unsigned cmp_type = flags & AF_CMP_TYPE_MASK;
201 } else if (cc != AF_CC_NE)
204 value *s = a->src[0];
206 bool_op_info bop = {};
214 if (!get_bool_op_info(s, bop))
223 sblog << "cndcc def: ";
229 unsigned dflags = d->bc.op_ptr->flags;
230 unsigned dcc = dflags & AF_CC_MASK;
231 unsigned dcmp_type = dflags & AF_CMP_TYPE_MASK;
232 unsigned ddst_type = dflags & AF_DST_TYPE_MASK;
235 // TODO we can handle some of these cases,
236 // though probably this shouldn't happen
237 if (cmp_type != AF_FLOAT_CMP && ddst_type == AF_FLOAT_DST)
240 if (d->src[0]->is_const() && d->src[0]->literal_value == literal(0))
242 else if ((d->src[1]->is_const() &&
243 d->src[1]->literal_value == literal(0)))
248 // can't propagate ABS modifier to CNDcc because it's OP3
249 if (d->bc.src[nds].abs)
252 // TODO we can handle some cases for uint comparison
253 if (dcmp_type == AF_UINT_CMP)
256 if (dcc == AF_CC_NE) {
263 case AF_CC_GT: dcc = AF_CC_GE; swap = !swap; break;
264 case AF_CC_GE: dcc = AF_CC_GT; swap = !swap; break;
269 a->src[0] = d->src[nds];
270 a->bc.src[0] = d->bc.src[nds];
273 std::swap(a->src[1], a->src[2]);
274 std::swap(a->bc.src[1], a->bc.src[2]);
277 a->bc.set_op(get_cndcc_op(dcc, dcmp_type));
281 bool peephole::get_bool_flt_to_int_source(alu_node* &a) {
283 if (a->bc.op == ALU_OP1_FLT_TO_INT) {
285 if (a->bc.src[0].neg || a->bc.src[0].abs || a->bc.src[0].rel)
288 value *s = a->src[0];
289 if (!s || !s->def || !s->def->is_alu_inst())
292 alu_node *dn = static_cast<alu_node*>(s->def);
294 if (dn->is_alu_op(ALU_OP1_TRUNC)) {
296 if (!s || !s->def || !s->def->is_alu_inst())
299 if (dn->bc.src[0].neg != 1 || dn->bc.src[0].abs != 0 ||
300 dn->bc.src[0].rel != 0) {
304 dn = static_cast<alu_node*>(s->def);
308 if (dn->bc.op_ptr->flags & AF_SET) {
316 bool peephole::get_bool_op_info(value* b, bool_op_info& bop) {
320 if (!d || !d->is_alu_inst())
323 alu_node *dn = static_cast<alu_node*>(d);
325 if (dn->bc.op_ptr->flags & AF_SET) {
328 if (dn->bc.op_ptr->flags & AF_DX10)
334 if (get_bool_flt_to_int_source(dn)) {
343 } // namespace r600_sb