diff --git a/src/gallium/drivers/r600/sb/sb_dce_cleanup.cpp b/src/gallium/drivers/r600/sb/sb_dce_cleanup.cpp index 79aef91..248be84 100644 --- a/src/gallium/drivers/r600/sb/sb_dce_cleanup.cpp +++ b/src/gallium/drivers/r600/sb/sb_dce_cleanup.cpp @@ -30,6 +30,19 @@ namespace r600_sb { +int dce_cleanup::run() { + int r; + + // TODO Limit iterations? Probably would need to harden gcm pass due to + // kept unused ops, though. + do { + nodes_changed = false; + r = vpass::run(); + } while (r == 0 && nodes_changed); + + return r; +} + bool dce_cleanup::visit(node& n, bool enter) { if (enter) { } else { @@ -108,9 +121,28 @@ bool dce_cleanup::visit(region_node& n, bool enter) { } void dce_cleanup::cleanup_dst(node& n) { + //sblog << "cleanup_dst(remove_unused=" << remove_unused << "): "; + //dump::dump_op(&n); + //sblog << "\n"; if (!cleanup_dst_vec(n.dst) && remove_unused && !n.dst.empty() && !(n.flags & NF_DONT_KILL) && n.parent) + { + // Remove reference to removed op from src values, to allow for + // additional removes. + for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) { + value* v = *I; + if (v && v->def && v->uses.size()) + { + //dump::dump_op(v->any_def()); + //sblog << " uc: " << v->use_count() << "\n"; + v->remove_use(&n); + //dump::dump_op(v->any_def()); + //sblog << " uc: " << v->use_count() << "\n"; + } + } n.remove(); + nodes_changed = true; + } } bool dce_cleanup::visit(container_node& n, bool enter) { @@ -130,12 +162,13 @@ bool dce_cleanup::cleanup_dst_vec(vvec& vv) { if (v->gvn_source && v->gvn_source->is_dead()) v->gvn_source = NULL; - if (v->is_dead() || (remove_unused && !v->is_rel() && !v->uses)) + if (v->is_dead() || (remove_unused && !v->is_rel() && !v->uses.size())) v = NULL; else alive = true; } + //sblog << "cleanup_dst_vec: alive=" << alive << "\n"; return alive; } diff --git a/src/gallium/drivers/r600/sb/sb_expr.cpp b/src/gallium/drivers/r600/sb/sb_expr.cpp index 3dd3a48..4ebf8a0 100644 --- a/src/gallium/drivers/r600/sb/sb_expr.cpp +++ b/src/gallium/drivers/r600/sb/sb_expr.cpp @@ -26,7 +26,10 @@ #include +#include "sb_bc.h" #include "sb_shader.h" +#include "sb_pass.h" +#include "sb_sched.h" namespace r600_sb { @@ -570,11 +573,11 @@ bool expr_handler::eval_const_op(unsigned op, literal &r, case ALU_OP2_MUL: case ALU_OP2_MUL_IEEE: r = cv0.f * cv1.f; break; case ALU_OP2_MULHI_INT: - r = (int32_t)(((int64_t)cv0.u * cv1.u)>>32); break; + r = (int32_t)(((int64_t)cv0.i * cv1.i)>>32); break; case ALU_OP2_MULHI_UINT: r = (uint32_t)(((uint64_t)cv0.u * cv1.u)>>32); break; case ALU_OP2_MULLO_INT: - r = (int32_t)(((int64_t)cv0.u * cv1.u) & 0xFFFFFFFF); break; + r = (int32_t)(((int64_t)cv0.i * cv1.i) & 0xFFFFFFFF); break; case ALU_OP2_MULLO_UINT: r = (uint32_t)(((uint64_t)cv0.u * cv1.u) & 0xFFFFFFFF); break; case ALU_OP2_OR_INT: r = cv0.i | cv1.i; break; @@ -714,6 +722,8 @@ bool expr_handler::fold_assoc(alu_node *n) { n->src.resize(2); n->bc.set_op(ALU_OP2_ADD); + // TODO verify if 3 op -> 2 op conversion does need true + //return true; } } else if (last_arg >= 0) { n->src[0] = a->src[last_arg]; diff --git a/src/gallium/drivers/r600/sb/sb_gcm.cpp b/src/gallium/drivers/r600/sb/sb_gcm.cpp index 236b2ea..ae8bb1b 100644 --- a/src/gallium/drivers/r600/sb/sb_gcm.cpp +++ b/src/gallium/drivers/r600/sb/sb_gcm.cpp @@ -199,10 +199,9 @@ void gcm::td_release_val(value *v) { sblog << "\n"; ); - use_info *u = v->uses; - while (u) { + for (uselist::iterator I = v->uses.begin(), E = v->uses.end(); I != E; ++I) { + use_info *u = *I; if (u->op->parent != &pending) { - u = u->next; continue; } @@ -212,6 +211,7 @@ void gcm::td_release_val(value *v) { sblog << "\n"; ); + assert(uses[u->op] > 0); if (--uses[u->op] == 0) { GCM_DUMP( sblog << "td released : "; @@ -222,7 +222,6 @@ void gcm::td_release_val(value *v) { pending.remove_node(u->op); ready.push_back(u->op); } - u = u->next; } } diff --git a/src/gallium/drivers/r600/sb/sb_ir.cpp b/src/gallium/drivers/r600/sb/sb_ir.cpp index 5226893..d989dce 100644 --- a/src/gallium/drivers/r600/sb/sb_ir.cpp +++ b/src/gallium/drivers/r600/sb/sb_ir.cpp @@ -255,7 +255,7 @@ void container_node::expand() { void node::remove() {parent->remove_node(this); } -value_hash node::hash_src() { +value_hash node::hash_src() const { value_hash h = 12345; @@ -269,7 +269,7 @@ value_hash node::hash_src() { } -value_hash node::hash() { +value_hash node::hash() const { if (parent && parent->subtype == NST_LOOP_PHI_CONTAINER) return 47451; diff --git a/src/gallium/drivers/r600/sb/sb_ir.h b/src/gallium/drivers/r600/sb/sb_ir.h index 4fc4da2..74c0549 100644 --- a/src/gallium/drivers/r600/sb/sb_ir.h +++ b/src/gallium/drivers/r600/sb/sb_ir.h @@ -446,15 +446,16 @@ enum use_kind { }; struct use_info { - use_info *next; node *op; use_kind kind; int arg; - use_info(node *n, use_kind kind, int arg, use_info* next) - : next(next), op(n), kind(kind), arg(arg) {} + use_info(node *n, use_kind kind, int arg) + : op(n), kind(kind), arg(arg) {} }; +typedef std::list< use_info * > uselist; + enum constraint_kind { CK_SAME_REG, CK_PACKED_BS, @@ -498,7 +499,7 @@ public: value_hash ghash; node *def, *adef; - use_info *uses; + uselist uses; ra_constraint *constraint; ra_chunk *chunk; @@ -585,6 +586,7 @@ public: } void add_use(node *n, use_kind kind, int arg); + void remove_use(const node *n); value_hash hash(); value_hash rel_hash(); @@ -790,8 +792,8 @@ public: void replace_with(node *n); void remove(); - virtual value_hash hash(); - value_hash hash_src(); + virtual value_hash hash() const; + value_hash hash_src() const; virtual bool fold_dispatch(expr_handler *ex); diff --git a/src/gallium/drivers/r600/sb/sb_pass.h b/src/gallium/drivers/r600/sb/sb_pass.h index 0346df1..e878f8c 100644 --- a/src/gallium/drivers/r600/sb/sb_pass.h +++ b/src/gallium/drivers/r600/sb/sb_pass.h @@ -124,7 +124,9 @@ class dce_cleanup : public vpass { public: dce_cleanup(shader &s) : vpass(s), - remove_unused(s.dce_flags & DF_REMOVE_UNUSED) {} + remove_unused(s.dce_flags & DF_REMOVE_UNUSED), nodes_changed(false) {} + + virtual int run(); virtual bool visit(node &n, bool enter); virtual bool visit(alu_group_node &n, bool enter); @@ -140,6 +142,8 @@ private: void cleanup_dst(node &n); bool cleanup_dst_vec(vvec &vv); + // Did we alter/remove nodes during a single pass? + bool nodes_changed; }; diff --git a/src/gallium/drivers/r600/sb/sb_valtable.cpp b/src/gallium/drivers/r600/sb/sb_valtable.cpp index eb242b1..cdc1c64 100644 --- a/src/gallium/drivers/r600/sb/sb_valtable.cpp +++ b/src/gallium/drivers/r600/sb/sb_valtable.cpp @@ -213,24 +231,43 @@ void value_table::get_values(vvec& v) { } void value::add_use(node* n, use_kind kind, int arg) { - if (0) { + if (0) { sblog << "add_use "; dump::dump_val(this); sblog << " => "; dump::dump_op(n); sblog << " kind " << kind << " arg " << arg << "\n"; } - uses = new use_info(n, kind, arg, uses); + uses.push_back(new use_info(n, kind, arg)); } -unsigned value::use_count() { - use_info *u = uses; - unsigned c = 0; - while (u) { - ++c; - u = u->next; + bool use_node(const node *n, const use_info* u) + { + return u->op == n; + } + +struct use_node_comp { + explicit use_node_comp(const node *n) : n(n) {} + bool operator() (const use_info *u) { + return u->op->hash() == n->hash(); + } + + private: + const node *n; +}; + +void value::remove_use(const node *n) { + uselist::iterator it = std::find_if(uses.begin(), uses.end(), use_node_comp(n)); + if (it != uses.end()) + { + //assert((*it)->kind == kind); + //assert((*it)->arg == arg); + uses.erase(it); } - return c; +} + +unsigned value::use_count() { + return uses.size(); } bool value::is_global() { @@ -274,13 +311,7 @@ bool value::is_prealloc() { } void value::delete_uses() { - use_info *u, *c = uses; - while (c) { - u = c->next; - delete c; - c = u; - } - uses = NULL; + uses.erase(uses.begin(), uses.end()); } void ra_constraint::update_values() { @@ -468,7 +499,7 @@ bool r600_sb::sb_value_set::add_vec(vvec& vv) { bool r600_sb::sb_value_set::contains(value* v) { unsigned b = v->uid - 1; if (b < bs.size()) - return bs.get(v->uid - 1); + return bs.get(b); else return false; }