nvc0: make sure phi-ops really have one source per in-block
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Mon, 7 Feb 2011 20:17:37 +0000 (21:17 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Wed, 9 Feb 2011 15:05:00 +0000 (16:05 +0100)
src/gallium/drivers/nvc0/nvc0_pc.h
src/gallium/drivers/nvc0/nvc0_pc_regalloc.c

index 0756288daf7b034a6a0f23a91032ba0b25c0e235..40d728aefc7638d0732420d8149f0c2327b05272 100644 (file)
@@ -345,6 +345,8 @@ struct nv_ref {
    uint8_t flags;
 };
 
+#define NV_REF_FLAG_REGALLOC_PRIV (1 << 0)
+
 struct nv_basic_block;
 
 struct nv_instruction {
index ee2826800611e19f67b022cd0239b7595f52bb01..718943bdbdfbe372b02a30bac5dbb03c06fb350d 100644 (file)
@@ -360,20 +360,32 @@ need_new_else_block(struct nv_basic_block *b, struct nv_basic_block *p)
    return (b->num_in > 1) && (n == 2);
 }
 
+/* Look for the @phi's operand whose definition reaches @b. */
 static int
 phi_opnd_for_bb(struct nv_instruction *phi, struct nv_basic_block *b,
                 struct nv_basic_block *tb)
 {
+   struct nv_ref *srci, *srcj;
    int i, j;
 
    for (j = -1, i = 0; i < 6 && phi->src[i]; ++i) {
-      if (!nvc0_bblock_reachable_by(b, phi->src[i]->value->insn->bb, tb))
+      srci = phi->src[i];
+      /* if already replaced, check with original source first */
+      if (srci->flags & NV_REF_FLAG_REGALLOC_PRIV)
+         srci = srci->value->insn->src[0];
+      if (!nvc0_bblock_reachable_by(b, srci->value->insn->bb, NULL))
          continue;
       /* NOTE: back-edges are ignored by the reachable-by check */
-      if (j < 0 || !nvc0_bblock_reachable_by(phi->src[j]->value->insn->bb,
-                                             phi->src[i]->value->insn->bb, tb))
+      if (j < 0 || !nvc0_bblock_reachable_by(srcj->value->insn->bb,
+                                             srci->value->insn->bb, NULL)) {
          j = i;
+         srcj = srci;
+      }
    }
+   if (j >= 0 && nvc0_bblock_reachable_by(b, phi->def[0]->insn->bb, NULL))
+      if (!nvc0_bblock_reachable_by(srcj->value->insn->bb,
+                                    phi->def[0]->insn->bb, NULL))
+         j = -1;
    return j;
 }
 
@@ -420,21 +432,23 @@ pass_generate_phi_movs(struct nv_pc_pass *ctx, struct nv_basic_block *b)
       ctx->pc->current_block = pn;
 
       for (i = b->phi; i && i->opcode == NV_OP_PHI; i = i->next) {
-         if ((j = phi_opnd_for_bb(i, p, b)) < 0)
-            continue;
-         val = i->src[j]->value;
-
-         if (i->src[j]->flags) {
-            /* value already encountered from a different in-block */
-            val = val->insn->src[0]->value;
-            while (j < 6 && i->src[j])
-               ++j;
-            assert(j < 6);
+         j = phi_opnd_for_bb(i, p, b);
+
+         if (j < 0) {
+            val = i->def[0];
+         } else {
+            val = i->src[j]->value;
+            if (i->src[j]->flags & NV_REF_FLAG_REGALLOC_PRIV) {
+               j = -1;
+               /* use original value, we already encountered & replaced it */
+               val = val->insn->src[0]->value;
+            }
          }
+         if (j < 0) /* need an additional source ? */
+            for (j = 0; j < 6 && i->src[j] && i->src[j]->value != val; ++j);
+         assert(j < 6); /* XXX: really ugly shaders */
 
          ni = new_instruction(ctx->pc, NV_OP_MOV);
-
-         /* TODO: insert instruction at correct position in the first place */
          if (ni->prev && ni->prev->target)
             nvc0_insns_permute(ni->prev, ni);
 
@@ -442,7 +456,7 @@ pass_generate_phi_movs(struct nv_pc_pass *ctx, struct nv_basic_block *b)
          ni->def[0]->insn = ni;
          nv_reference(ctx->pc, ni, 0, val);
          nv_reference(ctx->pc, i, j, ni->def[0]); /* new phi source = MOV def */
-         i->src[j]->flags = 1;
+         i->src[j]->flags |= NV_REF_FLAG_REGALLOC_PRIV;
       }
 
       if (pn != p && pn->exit) {
@@ -619,15 +633,16 @@ static void collect_live_values(struct nv_basic_block *b, const int n)
 {
    int i;
 
-   if (b->out[0]) {
-      if (b->out[1]) { /* what to do about back-edges ? */
+   /* XXX: what to do about back/fake-edges (used to include both here) ? */
+   if (b->out[0] && b->out_kind[0] != CFG_EDGE_FAKE) {
+      if (b->out[1] && b->out_kind[1] != CFG_EDGE_FAKE) {
          for (i = 0; i < n; ++i)
             b->live_set[i] = b->out[0]->live_set[i] | b->out[1]->live_set[i];
       } else {
          memcpy(b->live_set, b->out[0]->live_set, n * sizeof(uint32_t));
       }
    } else
-   if (b->out[1]) {
+   if (b->out[1] && b->out_kind[1] != CFG_EDGE_FAKE) {
       memcpy(b->live_set, b->out[1]->live_set, n * sizeof(uint32_t));
    } else {
       memset(b->live_set, 0, n * sizeof(uint32_t));
@@ -877,6 +892,10 @@ nv_pc_pass1(struct nv_pc *pc, struct nv_basic_block *root)
    ret = pass_generate_phi_movs(ctx, root);
    assert(!ret);
 
+#ifdef NVC0_RA_DEBUG_LIVEI
+   nvc0_print_function(root);
+#endif
+
    for (i = 0; i < pc->loop_nesting_bound; ++i) {
       pc->pass_seq++;
       ret = pass_build_live_sets(ctx, root);