nv50: make sure half-long insns are paired
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 23 May 2009 13:10:01 +0000 (15:10 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 28 May 2009 06:06:21 +0000 (16:06 +1000)
I chose to just convert unpaired 32 bit length instructions
after parsing all instructions, although it might be possible
to determine beforehand whether there would be any lone ones,
and then even do some swapping to bring them together ...

src/gallium/drivers/nv50/nv50_program.c

index c420b8be1c336d4a6bf4f1b675c735ccd6b0d6af..78ffc7f7ce9fa0e1e624726101fa63961bd53347 100644 (file)
@@ -945,6 +945,54 @@ emit_kil(struct nv50_pc *pc, struct nv50_reg *src)
        emit(pc, e);
 }
 
+static void
+convert_to_long(struct nv50_pc *pc, struct nv50_program_exec *e)
+{
+       unsigned q = 0, m = ~0;
+
+       assert(!is_long(e));
+
+       switch (e->inst[0] >> 28) {
+       case 0x1:
+               /* MOV */
+               q = 0x0403c000;
+               m = 0xffff7fff;
+               break;
+       case 0x8:
+               /* INTERP */
+               m = ~0x02000000;
+               if (e->inst[0] & 0x02000000)
+                       q = 0x00020000;
+               break;
+       case 0x9:
+               /* RCP */
+               break;
+       case 0xB:
+               /* ADD */
+               m = ~(127 << 16);
+               q = ((e->inst[0] & (~m)) >> 2);
+               break;
+       case 0xC:
+               /* MUL */
+               m = ~0x00008000;
+               q = ((e->inst[0] & (~m)) << 12);
+               break;
+       case 0xE:
+               /* MAD (if src2 == dst) */
+               q = ((e->inst[0] & 0x1fc) << 12);
+               break;
+       default:
+               assert(0);
+               break;
+       }
+
+       set_long(pc, e);
+       pc->p->exec_size++;
+
+       e->inst[0] &= m;
+       e->inst[1] |= q;
+}
+
 static struct nv50_reg *
 tgsi_dst(struct nv50_pc *pc, int c, const struct tgsi_full_dst_register *dst)
 {
@@ -1971,6 +2019,30 @@ nv50_program_tx(struct nv50_program *p)
                }
        }
 
+       /* look for single half instructions and make them long */
+       struct nv50_program_exec *e, *e_prev;
+
+       for (k = 0, e = pc->p->exec_head, e_prev = NULL; e; e = e->next) {
+               if (!is_long(e))
+                       k++;
+
+               if (!e->next || is_long(e->next)) {
+                       if (k & 1)
+                               convert_to_long(pc, e);
+                       k = 0;
+               }
+
+               if (e->next)
+                       e_prev = e;
+       }
+
+       if (!is_long(pc->p->exec_tail)) {
+               /* this may occur if moving FP results */
+               assert(e_prev && !is_long(e_prev));
+               convert_to_long(pc, e_prev);
+               convert_to_long(pc, pc->p->exec_tail);
+       }
+
        assert(is_long(pc->p->exec_tail) && !is_immd(pc->p->exec_head));
        pc->p->exec_tail->inst[1] |= 0x00000001;