/* * Copyright 2013 Vadim Girlin * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Vadim Girlin */ #define IFC_DEBUG 0 #if IFC_DEBUG #define IFC_DUMP(q) do { q } while (0) #else #define IFC_DUMP(q) #endif #include "sb_shader.h" #include "sb_pass.h" #include "sb_if_conversion.h" namespace r600_sb { using std::cerr; int r600_sb::if_conversion::run() { regions_vec &rv = sh.get_regions(); unsigned converted = 0; for (regions_vec::reverse_iterator N, I = rv.rbegin(), E = rv.rend(); I != E; I = N) { N = I; ++N; region_node *r = *I; if (run_on(r)) { rv.erase(I.base() - 1); ++converted; } } return 0; } bool r600_sb::if_conversion::run_on(region_node* r) { if (!r->phi) return false; if (r->dep_count() != 2 || r->rep_count() != 1) return false; node_stats s; r->collect_stats(s); IFC_DUMP( cerr << "ifcvt: region " << r->region_id << " :\n"; s.dump(); ); if (s.alu_kill_count || s.region_count || s.fetch_count || s.if_count != 1 || s.repeat_count) return false; if (s.alu_count > 32) return false; depart_node *nd1 = static_cast(r->first); if (!nd1->is_depart()) return false; if_node *nif = static_cast(nd1->first); if (!nif->is_if()) return false; depart_node *nd2 = static_cast(nif->first); if (!nd2->is_depart()) return false; value *em = nif->cond; value *select = get_select_value_for_em(sh, em); if (!select) return false; for (node_iterator I = r->phi->begin(), E = r->phi->end(); I != E; ++I) { node *n = *I; alu_node *ns = convert_phi(select, n); if (ns) r->insert_after(ns); } nd2->expand(); nif->expand(); nd1->expand(); r->expand(); return true; } alu_node* if_conversion::convert_phi(value* select, node* phi) { assert(phi->dst.size() == 1 || phi->src.size() == 2); value *d = phi->dst[0]; value *v1 = phi->src[0]; value *v2 = phi->src[1]; assert(d); if (!d->is_any_gpr()) return NULL; if (v1->is_undef()) { if (v2->is_undef()) { return NULL; } else { return sh.create_mov(d, v2); } } else if (v2->is_undef()) return sh.create_mov(d, v1); alu_node* n = sh.create_alu(); n->bc.set_op(ALU_OP3_CNDE_INT); n->dst.push_back(d); n->src.push_back(select); n->src.push_back(v1); n->src.push_back(v2); return n; } } // namespace r600_sb