nv50/ir: Add convenience method for calculating the live sets of a function.
[mesa.git] / src / gallium / drivers / nv50 / nv50_pc.c
index 26ad9b4e3db9e0c063d1e03b74d170c5e72eb4e0..9137f871f5a7be643cded5daa994cc782be875c9 100644 (file)
@@ -20,8 +20,6 @@
  * SOFTWARE.
  */
 
-/* #define NV50PC_DEBUG */
-
 #include "nv50_pc.h"
 #include "nv50_program.h"
 
@@ -57,6 +55,7 @@ nv50_indirect_opnd(struct nv_instruction *i)
    switch (i->opcode) {
    case NV_OP_MOV:
    case NV_OP_LDA:
+   case NV_OP_STA:
       return 0;
    default:
       return 1;
@@ -103,6 +102,8 @@ nv50_nvi_can_load(struct nv_instruction *nvi, int s, struct nv_value *value)
    case NV_OP_FLOOR:
    case NV_OP_TRUNC:
    case NV_OP_CVT:
+   case NV_OP_ROUND:
+   case NV_OP_NEG:
    case NV_OP_MAD:
    case NV_OP_MUL:
    case NV_OP_SAT:
@@ -169,6 +170,28 @@ nv50_supported_src_mods(uint opcode, int s)
    }
 }
 
+/* We may want an opcode table. */
+boolean
+nv50_op_can_write_flags(uint opcode)
+{
+   if (nv_is_vector_op(opcode))
+      return FALSE;
+   switch (opcode) { /* obvious ones like KIL, CALL, etc. not included */
+   case NV_OP_PHI:
+   case NV_OP_MOV:
+   case NV_OP_SELECT:
+   case NV_OP_LINTERP:
+   case NV_OP_PINTERP:
+   case NV_OP_LDA:
+      return FALSE;
+   default:
+      break;
+   }
+   if (opcode >= NV_OP_RCP && opcode <= NV_OP_PREEX2)
+      return FALSE;
+   return TRUE;
+}
+
 int
 nv_nvi_refcount(struct nv_instruction *nvi)
 {
@@ -284,7 +307,10 @@ nv_pc_pass_in_order(struct nv_basic_block *root, nv_pc_pass_func f, void *priv)
             bb[p++] = b->out[j];
             break;
          case CFG_EDGE_LOOP_LEAVE:
-            bbb[pp++] = b->out[j];
+            if (!b->out[j]->priv) {
+               bbb[pp++] = b->out[j];
+               b->out[j]->priv = 1;
+            }
             break;
          default:
             assert(0);
@@ -305,7 +331,7 @@ nv_pc_pass_in_order(struct nv_basic_block *root, nv_pc_pass_func f, void *priv)
 static void
 nv_do_print_function(void *priv, struct nv_basic_block *b)
 {
-   struct nv_instruction *i = b->phi;
+   struct nv_instruction *i;
 
    debug_printf("=== BB %i ", b->id);
    if (b->out[0])
@@ -341,7 +367,7 @@ nv_print_program(struct nv_pc *pc)
          nv_print_function(pc->root[i]);
 }
 
-#ifdef NV50_PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_CFLOW
 static void
 nv_do_print_cfgraph(struct nv_pc *pc, FILE *f, struct nv_basic_block *b)
 {
@@ -399,15 +425,18 @@ nv_print_cfgraph(struct nv_pc *pc, const char *filepath, int subr)
 
    fclose(f);
 }
-#endif
+#endif /* NV50_DEBUG_PROG_CFLOW */
 
 static INLINE void
 nvcg_show_bincode(struct nv_pc *pc)
 {
-   int i;
+   unsigned i;
 
-   for (i = 0; i < pc->bin_size / 4; ++i)
+   for (i = 0; i < pc->bin_size / 4; ++i) {
       debug_printf("0x%08x ", pc->emit[i]);
+      if ((i % 16) == 15)
+         debug_printf("\n");
+   }
    debug_printf("\n");
 }
 
@@ -417,7 +446,7 @@ nv50_emit_program(struct nv_pc *pc)
    uint32_t *code = pc->emit;
    int n;
 
-   NV50_DBGMSG("emitting program: size = %u\n", pc->bin_size);
+   NV50_DBGMSG(SHADER, "emitting program: size = %u\n", pc->bin_size);
 
    for (n = 0; n < pc->num_blocks; ++n) {
       struct nv_instruction *i;
@@ -433,7 +462,8 @@ nv50_emit_program(struct nv_pc *pc)
    assert(pc->emit == &code[pc->bin_size / 4]);
 
    /* XXX: we can do better than this ... */
-   if (!(pc->emit[-2] & 1) || (pc->emit[-2] & 2) || (pc->emit[-1] & 3)) {
+   if (!pc->bin_size ||
+       !(pc->emit[-2] & 1) || (pc->emit[-2] & 2) || (pc->emit[-1] & 3)) {
       pc->emit[0] = 0xf0000001;
       pc->emit[1] = 0xe0000000;
       pc->bin_size += 8;
@@ -442,7 +472,7 @@ nv50_emit_program(struct nv_pc *pc)
    pc->emit = code;
    code[pc->bin_size / 4 - 1] |= 1;
 
-#ifdef NV50PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_SHADER
    nvcg_show_bincode(pc);
 #endif
 
@@ -470,7 +500,7 @@ nv50_generate_code(struct nv50_translation_info *ti)
    ret = nv50_tgsi_to_nc(pc, ti);
    if (ret)
       goto out;
-#ifdef NV50PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_IR
    nv_print_program(pc);
 #endif
 
@@ -480,7 +510,7 @@ nv50_generate_code(struct nv50_translation_info *ti)
    ret = nv_pc_exec_pass0(pc);
    if (ret)
       goto out;
-#ifdef NV50PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_IR
    nv_print_program(pc);
 #endif
 
@@ -488,7 +518,7 @@ nv50_generate_code(struct nv50_translation_info *ti)
    ret = nv_pc_exec_pass1(pc);
    if (ret)
       goto out;
-#ifdef NV50PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_CFLOW
    nv_print_program(pc);
    nv_print_cfgraph(pc, "nv50_shader_cfgraph.dot", 0);
 #endif
@@ -497,6 +527,7 @@ nv50_generate_code(struct nv50_translation_info *ti)
    ret = nv_pc_exec_pass2(pc);
    if (ret)
       goto out;
+   assert(!(pc->bin_size % 8));
 
    pc->emit = CALLOC(pc->bin_size / 4 + 2, 4);
    if (!pc->emit) {
@@ -513,13 +544,15 @@ nv50_generate_code(struct nv50_translation_info *ti)
    ti->p->immd_size = pc->immd_count * 4;
    ti->p->immd = pc->immd_buf;
 
-   /* highest 16 bit reg to num of 32 bit regs */
-   ti->p->max_gpr = (pc->max_reg[NV_FILE_GPR] >> 1) + 1;
+   /* highest 16 bit reg to num of 32 bit regs, limit to >= 4 */
+   ti->p->max_gpr = MAX2(4, (pc->max_reg[NV_FILE_GPR] >> 1) + 1);
 
    ti->p->fixups = pc->fixups;
    ti->p->num_fixups = pc->num_fixups;
 
-   NV50_DBGMSG("SHADER TRANSLATION - %s\n", ret ? "failure" : "success");
+   ti->p->uses_lmem = ti->store_to_memory;
+
+   NV50_DBGMSG(SHADER, "SHADER TRANSLATION - %s\n", ret ? "failed" : "success");
 
 out:
    nv_pc_free_refs(pc);
@@ -591,6 +624,9 @@ nvbb_insert_tail(struct nv_basic_block *b, struct nv_instruction *i)
 
    i->bb = b;
    b->num_instructions++;
+
+   if (i->prev && i->prev->is_terminator)
+      nv_nvi_permute(i->prev, i);
 }
 
 void
@@ -636,7 +672,7 @@ nv_nvi_delete(struct nv_instruction *nvi)
 
    if (nvi == b->phi) {
       if (nvi->opcode != NV_OP_PHI)
-         NV50_DBGMSG("NOTE: b->phi points to non-PHI instruction\n");
+         NV50_DBGMSG(PROG_IR, "NOTE: b->phi points to non-PHI instruction\n");
 
       assert(!nvi->prev);
       if (!nvi->next || nvi->next->opcode != NV_OP_PHI)