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 */
}
}
+/* 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)
{
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)
case midgard_reg_mode_64:
return 64;
default:
+ unreachable("Invalid reg mode");
return 0;
}
}
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;
reg_info->src2_reg, override, is_int);
}
+ midg_stats.instruction_count++;
printf("\n");
}
} else
print_scalar_src(alu_field->src2, reg_info->src2_reg);
+ midg_stats.instruction_count++;
printf("\n");
}
break;
}
}
+
+ midg_stats.instruction_count++;
}
static void
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);
printf("%d -> ", br.offset);
print_tag_short(br.dest_tag);
printf("\n");
+
+ midg_stats.instruction_count++;
}
static unsigned
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)
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;
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
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)
{
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;
}
}
/* Specific format in question */
print_texture_format(texture->format);
- assert(texture->zero == 0);
-
/* Instruction "modifiers" parallel the ALU instructions. */
if (texture->shadow)
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(", ");
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
/* 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;
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;
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;
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 */
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;
}