pan/midgard: Sketch static analysis to uniform count
[mesa.git] / src / panfrost / midgard / disassemble.c
index acc1f408e98a30470322fac3f1d6015d62702934..7a95878d0f432f2c13e9e0866e1e478cb0c2c22d 100644 (file)
 
 static bool is_instruction_int = false;
 
+/* Stats */
+
+static struct midgard_disasm_stats midg_stats;
+
 /* Prints a short form of the tag for branching, the minimum needed to be
  * legible and unambiguous */
 
@@ -110,6 +114,12 @@ prefix_for_bits(unsigned bits)
         }
 }
 
+/* For static analysis to ensure all registers are written at least once before
+ * use along the source code path (TODO: does this break done for complex CF?)
+ */
+
+uint16_t midg_ever_written = 0;
+
 static void
 print_reg(unsigned reg, unsigned bits)
 {
@@ -120,6 +130,27 @@ print_reg(unsigned reg, unsigned bits)
                 is_embedded_constant_half = (bits < 32);
         }
 
+        unsigned uniform_reg = 23 - reg;
+        bool is_uniform = false;
+
+        /* For r8-r15, it could be a work or uniform. We distinguish based on
+         * the fact work registers are ALWAYS written before use, but uniform
+         * registers are NEVER written before use. */
+
+        if ((reg >= 8 && reg < 16) && !(midg_ever_written & (1 << reg)))
+                is_uniform = true;
+
+        /* r16-r23 are always uniform */
+
+        if (reg >= 16 && reg <= 23)
+                is_uniform = true;
+
+        /* Update the uniform count appropriately */
+
+        if (is_uniform)
+                midg_stats.uniform_count =
+                        MAX2(uniform_reg + 1, midg_stats.uniform_count);
+
         char prefix = prefix_for_bits(bits);
 
         if (prefix)
@@ -279,6 +310,7 @@ bits_for_mode(midgard_reg_mode mode)
         case midgard_reg_mode_64:
                 return 64;
         default:
+                unreachable("Invalid reg mode");
                 return 0;
         }
 }
@@ -411,6 +443,14 @@ print_mask(uint8_t mask, unsigned bits, midgard_dest_override override)
                 return;
         }
 
+        if (bits < 16) {
+                /* Shouldn't happen but with junk / out-of-spec shaders it
+                 * would cause an infinite loop */
+
+                printf("/* XXX: bits = %d */", bits);
+                return;
+        }
+
         /* Skip 'complete' masks */
 
         if (bits >= 32 && mask == 0xFF) return;
@@ -541,6 +581,7 @@ print_vector_field(const char *name, uint16_t *words, uint16_t reg_word,
                                  reg_info->src2_reg, override, is_int);
         }
 
+        midg_stats.instruction_count++;
         printf("\n");
 }
 
@@ -621,6 +662,7 @@ print_scalar_field(const char *name, uint16_t *words, uint16_t reg_word,
         } else
                 print_scalar_src(alu_field->src2, reg_info->src2_reg);
 
+        midg_stats.instruction_count++;
         printf("\n");
 }
 
@@ -728,6 +770,8 @@ print_compact_branch_writeout_field(uint16_t word)
                 break;
         }
         }
+
+        midg_stats.instruction_count++;
 }
 
 static void
@@ -740,15 +784,18 @@ print_extended_branch_writeout_field(uint8_t *words)
 
         print_branch_op(br.op);
 
-        /* Condition repeated 8 times in all known cases. Check this. */
+        /* Condition codes are a LUT in the general case, but simply repeated 8 times for single-channel conditions.. Check this. */
 
-        unsigned cond = br.cond & 0x3;
+        bool single_channel = true;
 
         for (unsigned i = 0; i < 16; i += 2) {
-                assert(((br.cond >> i) & 0x3) == cond);
+                single_channel &= (((br.cond >> i) & 0x3) == (br.cond & 0x3));
         }
 
-        print_branch_cond(cond);
+        if (single_channel)
+                print_branch_cond(br.cond & 0x3);
+        else
+                printf("lut%X", br.cond);
 
         if (br.unknown)
                 printf(".unknown%d", br.unknown);
@@ -761,6 +808,8 @@ print_extended_branch_writeout_field(uint8_t *words)
         printf("%d -> ", br.offset);
         print_tag_short(br.dest_tag);
         printf("\n");
+
+        midg_stats.instruction_count++;
 }
 
 static unsigned
@@ -965,6 +1014,37 @@ is_op_varying(unsigned op)
         return false;
 }
 
+static void
+print_load_store_arg(uint8_t arg, unsigned index)
+{
+        /* Try to interpret as a register */
+        midgard_ldst_register_select sel;
+        memcpy(&sel, &arg, sizeof(arg));
+
+        /* If unknown is set, we're not sure what this is or how to
+         * interpret it. But if it's zero, we get it. */
+
+        if (sel.unknown) {
+                printf("0x%02X", arg);
+                return;
+        }
+
+        unsigned reg = REGISTER_LDST_BASE + sel.select;
+        char comp = components[sel.component];
+
+        printf("r%d.%c", reg, comp);
+
+        /* Only print a shift if it's non-zero. Shifts only make sense for the
+         * second index. For the first, we're not sure what it means yet */
+
+        if (index == 1) {
+                if (sel.shift)
+                        printf(" << %d", sel.shift);
+        } else {
+                printf(" /* %X */", sel.shift);
+        }
+}
+
 static void
 print_load_store_instr(uint64_t data,
                        unsigned tabs)
@@ -981,8 +1061,10 @@ print_load_store_instr(uint64_t data,
 
         int address = word->address;
 
-        if (word->op == midgard_op_ld_uniform_32) {
-                /* Uniforms use their own addressing scheme */
+        bool is_ubo = OP_IS_UBO_READ(word->op);
+
+        if (is_ubo) {
+                /* UBOs use their own addressing scheme */
 
                 int lo = word->varying_parameters >> 7;
                 int hi = word->address;
@@ -995,7 +1077,18 @@ print_load_store_instr(uint64_t data,
 
         print_swizzle_vec4(word->swizzle, false, false);
 
-        printf(", 0x%X /* %X */\n", word->unknown, word->varying_parameters);
+        printf(", ");
+
+        if (is_ubo)
+                printf("ubo%d", word->arg_1);
+        else
+                print_load_store_arg(word->arg_1, 0);
+
+        printf(", ");
+        print_load_store_arg(word->arg_2, 1);
+        printf(" /* %X */\n", word->varying_parameters);
+
+        midg_stats.instruction_count++;
 }
 
 static void
@@ -1035,6 +1128,30 @@ print_texture_reg_triple(unsigned triple)
         print_texture_reg(full, select, upper);
 }
 
+static void
+print_texture_reg_select(uint8_t u)
+{
+        midgard_tex_register_select sel;
+        memcpy(&sel, &u, sizeof(u));
+
+        if (!sel.full)
+                printf("h");
+
+        printf("r%d", REG_TEX_BASE + sel.select);
+
+        unsigned component = sel.component;
+
+        /* Use the upper half in half-reg mode */
+        if (sel.upper) {
+                assert(!sel.full);
+                component += 4;
+        }
+
+        printf(".%c", components[component]);
+
+        assert(sel.zero == 0);
+}
+
 static void
 print_texture_format(int format)
 {
@@ -1074,9 +1191,11 @@ print_texture_op(unsigned op, bool gather)
                 DEFINE_CASE(TEXTURE_OP_NORMAL, "texture");
                 DEFINE_CASE(TEXTURE_OP_LOD, "textureLod");
                 DEFINE_CASE(TEXTURE_OP_TEXEL_FETCH, "texelFetch");
+                DEFINE_CASE(TEXTURE_OP_DFDX, "dFdx");
+                DEFINE_CASE(TEXTURE_OP_DFDY, "dFdy");
 
         default:
-                printf("tex_%d", op);
+                printf("tex_%X", op);
                 break;
         }
 }
@@ -1116,8 +1235,6 @@ print_texture_word(uint32_t *word, unsigned tabs)
         /* Specific format in question */
         print_texture_format(texture->format);
 
-        assert(texture->zero == 0);
-
         /* Instruction "modifiers" parallel the ALU instructions. */
 
         if (texture->shadow)
@@ -1129,17 +1246,34 @@ print_texture_word(uint32_t *word, unsigned tabs)
         if (texture->last)
                 printf(".last");
 
+        /* Output modifiers are always interpreted floatly */
+        print_outmod(texture->outmod, false);
+
         printf(" ");
 
         print_texture_reg(texture->out_full, texture->out_reg_select, texture->out_upper);
         print_mask_4(texture->mask);
         printf(", ");
 
-        printf("texture%d, ", texture->texture_handle);
+        if (texture->texture_register) {
+                printf("texture[");
+                print_texture_reg_select(texture->texture_handle);
+                printf("], ");
+        } else {
+                printf("texture%d, ", texture->texture_handle);
+        }
 
         /* Print the type, GL style */
-        printf("%c", sampler_type_name(texture->sampler_type));
-        printf("sampler%d", texture->sampler_handle);
+        printf("%csampler", sampler_type_name(texture->sampler_type));
+
+        if (texture->sampler_register) {
+                printf("[");
+                print_texture_reg_select(texture->sampler_handle);
+                printf("]");
+        } else {
+                printf("%d", texture->sampler_handle);
+        }
+
         print_swizzle_vec4(texture->swizzle, false, false);
         printf(", ");
 
@@ -1202,19 +1336,12 @@ print_texture_word(uint32_t *word, unsigned tabs)
         char lod_operand = texture_op_takes_bias(texture->op) ? '+' : '=';
 
         if (texture->lod_register) {
-                midgard_tex_register_select sel;
-                uint8_t raw = texture->bias;
-                memcpy(&sel, &raw, sizeof(raw));
-
                 printf("lod %c ", lod_operand);
-                print_texture_reg(sel.full, sel.select, sel.upper);
-                printf(".%c, ", components[sel.component]);
+                print_texture_reg_select(texture->bias);
+                printf(", ");
 
                 if (texture->bias_int)
                         printf(" /* bias_int = 0x%X */", texture->bias_int);
-
-                if (sel.zero)
-                        printf(" /* sel.zero = 0x%X */", sel.zero);
         } else if (texture->op == TEXTURE_OP_TEXEL_FETCH) {
                 /* For texel fetch, the int LOD is in the fractional place and
                  * there is no fraction / possibility of bias. We *always* have
@@ -1241,18 +1368,18 @@ print_texture_word(uint32_t *word, unsigned tabs)
         /* While not zero in general, for these simple instructions the
          * following unknowns are zero, so we don't include them */
 
-        if (texture->unknown2 ||
-            texture->unknown4 ||
+        if (texture->unknown4 ||
             texture->unknownA ||
             texture->unknown8) {
-                printf("// unknown2 = 0x%x\n", texture->unknown2);
                 printf("// unknown4 = 0x%x\n", texture->unknown4);
                 printf("// unknownA = 0x%x\n", texture->unknownA);
                 printf("// unknown8 = 0x%x\n", texture->unknown8);
         }
+
+        midg_stats.instruction_count++;
 }
 
-void
+struct midgard_disasm_stats
 disassemble_midgard(uint8_t *code, size_t size)
 {
         uint32_t *words = (uint32_t *) code;
@@ -1265,6 +1392,9 @@ disassemble_midgard(uint8_t *code, size_t size)
 
         unsigned i = 0;
 
+        /* Stats for shader-db */
+        memset(&midg_stats, 0, sizeof(midg_stats));
+
         while (i < num_words) {
                 unsigned tag = words[i] & 0xF;
                 unsigned next_tag = (words[i] >> 4) & 0xF;
@@ -1297,9 +1427,6 @@ disassemble_midgard(uint8_t *code, size_t size)
                 case midgard_word_type_alu:
                         print_alu_word(&words[i], num_quad_words, tabs);
 
-                        if (prefetch_flag)
-                                return;
-
                         /* Reset word static analysis state */
                         is_embedded_constant_half = false;
                         is_embedded_constant_int = false;
@@ -1314,11 +1441,16 @@ disassemble_midgard(uint8_t *code, size_t size)
                         break;
                 }
 
+                if (prefetch_flag && midgard_word_types[tag] == midgard_word_type_alu)
+                        break;
+
                 printf("\n");
 
                 unsigned next = (words[i] & 0xF0) >> 4;
 
-                i += 4 * num_quad_words;
+                /* We are parsing per bundle anyway */
+                midg_stats.bundle_count++;
+                midg_stats.quadword_count += num_quad_words;
 
                 /* Break based on instruction prefetch flag */
 
@@ -1326,9 +1458,11 @@ disassemble_midgard(uint8_t *code, size_t size)
                         prefetch_flag = true;
 
                         if (midgard_word_types[words[i] & 0xF] != midgard_word_type_alu)
-                                return;
+                                break;
                 }
+
+                i += 4 * num_quad_words;
         }
 
-        return;
+        return midg_stats;
 }