r600g/sb: fix issue with DCE between GVN and GCM (v2)
authorVadim Girlin <vadimgirlin@gmail.com>
Mon, 14 Oct 2013 13:19:12 +0000 (17:19 +0400)
committerVadim Girlin <vadimgirlin@gmail.com>
Thu, 17 Oct 2013 03:57:49 +0000 (07:57 +0400)
We can't perform DCE using the liveness pass between GVN and GCM
because it relies on the correct schedule, but GVN doesn't care about
preserving correctness - it's rescheduled later by GCM.

This patch makes dce_cleanup pass perform simple DCE
between GVN and GCM instead of relying on liveness pass.

Fixes https://bugs.freedesktop.org/show_bug.cgi?id=70088

Signed-off-by: Vadim Girlin <vadimgirlin@gmail.com>
src/gallium/drivers/r600/sb/sb_core.cpp
src/gallium/drivers/r600/sb/sb_dce_cleanup.cpp
src/gallium/drivers/r600/sb/sb_pass.h
src/gallium/drivers/r600/sb/sb_shader.h

index b5dd88ed96d19a1a812d42f0170296489140ddd6..9fd9d9ad25a2ec5e1312f00484f56d7900435be3 100644 (file)
@@ -184,6 +184,8 @@ int r600_sb_bytecode_process(struct r600_context *rctx,
                SB_RUN_PASS(psi_ops,            1);
 
        SB_RUN_PASS(liveness,                   0);
+
+       sh->dce_flags = DF_REMOVE_DEAD | DF_EXPAND;
        SB_RUN_PASS(dce_cleanup,                0);
        SB_RUN_PASS(def_use,                    0);
 
@@ -201,9 +203,10 @@ int r600_sb_bytecode_process(struct r600_context *rctx,
 
        SB_RUN_PASS(gvn,                                1);
 
-       SB_RUN_PASS(liveness,                   0);
+       SB_RUN_PASS(def_use,                    1);
+
+       sh->dce_flags = DF_REMOVE_DEAD | DF_REMOVE_UNUSED;
        SB_RUN_PASS(dce_cleanup,                1);
-       SB_RUN_PASS(def_use,                    0);
 
        SB_RUN_PASS(ra_split,                   0);
        SB_RUN_PASS(def_use,                    0);
@@ -217,6 +220,9 @@ int r600_sb_bytecode_process(struct r600_context *rctx,
        sh->compute_interferences = true;
        SB_RUN_PASS(liveness,                   0);
 
+       sh->dce_flags = DF_REMOVE_DEAD;
+       SB_RUN_PASS(dce_cleanup,                1);
+
        SB_RUN_PASS(ra_coalesce,                1);
        SB_RUN_PASS(ra_init,                    1);
 
index f879395f67c8327ddeddcaadcc92500ca03449e4..79aef9106a4f543bbcc553e19dc59e3eb68056cb 100644 (file)
@@ -56,7 +56,8 @@ bool dce_cleanup::visit(cf_node& n, bool enter) {
                else
                        cleanup_dst(n);
        } else {
-               if (n.bc.op_ptr->flags & (CF_CLAUSE | CF_BRANCH | CF_LOOP))
+               if ((sh.dce_flags & DF_EXPAND) &&
+                               (n.bc.op_ptr->flags & (CF_CLAUSE | CF_BRANCH | CF_LOOP)))
                        n.expand();
        }
        return true;
@@ -107,19 +108,20 @@ bool dce_cleanup::visit(region_node& n, bool enter) {
 }
 
 void dce_cleanup::cleanup_dst(node& n) {
-       cleanup_dst_vec(n.dst);
+       if (!cleanup_dst_vec(n.dst) && remove_unused &&
+                       !n.dst.empty() && !(n.flags & NF_DONT_KILL) && n.parent)
+               n.remove();
 }
 
 bool dce_cleanup::visit(container_node& n, bool enter) {
-       if (enter) {
+       if (enter)
                cleanup_dst(n);
-       } else {
-
-       }
        return true;
 }
 
-void dce_cleanup::cleanup_dst_vec(vvec& vv) {
+bool dce_cleanup::cleanup_dst_vec(vvec& vv) {
+       bool alive = false;
+
        for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
                value* &v = *I;
                if (!v)
@@ -128,9 +130,13 @@ void dce_cleanup::cleanup_dst_vec(vvec& vv) {
                if (v->gvn_source && v->gvn_source->is_dead())
                        v->gvn_source = NULL;
 
-               if (v->is_dead())
+               if (v->is_dead() || (remove_unused && !v->is_rel() && !v->uses))
                        v = NULL;
+               else
+                       alive = true;
        }
+
+       return alive;
 }
 
 } // namespace r600_sb
index 95d2a203a601c2b08baa40f96db2159edab5d984..a3f8515acdeae0ac02a6284bdf26d036920e587b 100644 (file)
@@ -119,9 +119,12 @@ public:
 class dce_cleanup : public vpass {
        using vpass::visit;
 
+       bool remove_unused;
+
 public:
 
-       dce_cleanup(shader &s) : vpass(s) {}
+       dce_cleanup(shader &s) : vpass(s),
+               remove_unused(s.dce_flags & DF_REMOVE_UNUSED) {}
 
        virtual bool visit(node &n, bool enter);
        virtual bool visit(alu_group_node &n, bool enter);
@@ -135,7 +138,7 @@ public:
 private:
 
        void cleanup_dst(node &n);
-       void cleanup_dst_vec(vvec &vv);
+       bool cleanup_dst_vec(vvec &vv);
 
 };
 
index e515d312d804e01fef380bcc06c55080e5c2bdbc..7955bba9b677c0ffdf3e01f9ac9c65fd346c1486 100644 (file)
@@ -71,6 +71,16 @@ enum chunk_flags {
        RCF_PREALLOC = (1 << 4)
 };
 
+enum dce_flags {
+       DF_REMOVE_DEAD  = (1 << 0),
+       DF_REMOVE_UNUSED = (1 << 1),
+       DF_EXPAND = (1 << 2),
+};
+
+inline dce_flags operator |(dce_flags l, dce_flags r) {
+       return (dce_flags)((unsigned)l|(unsigned)r);
+}
+
 inline chunk_flags operator |(chunk_flags l, chunk_flags r) {
        return (chunk_flags)((unsigned)l|(unsigned)r);
 }
@@ -297,6 +307,8 @@ public:
 
        unsigned ngpr, nstack;
 
+       unsigned dce_flags;
+
        shader(sb_context &sctx, shader_target t, unsigned id);
 
        ~shader();