[QOP_RCP] = { "rcp", 1, 1 },
[QOP_RSQ] = { "rsq", 1, 1 },
- [QOP_EXP2] = { "exp2", 1, 2 },
- [QOP_LOG2] = { "log2", 1, 2 },
- [QOP_TLB_STENCIL_SETUP] = { "tlb_stencil_setup", 0, 1, true },
- [QOP_TLB_Z_WRITE] = { "tlb_z", 0, 1, true },
- [QOP_TLB_COLOR_WRITE] = { "tlb_color", 0, 1, true },
- [QOP_TLB_COLOR_WRITE_MS] = { "tlb_color_ms", 0, 1, true },
+ [QOP_EXP2] = { "exp2", 1, 1 },
+ [QOP_LOG2] = { "log2", 1, 1 },
[QOP_TLB_COLOR_READ] = { "tlb_color_read", 1, 0 },
[QOP_MS_MASK] = { "ms_mask", 0, 1, true },
[QOP_VARY_ADD_C] = { "vary_add_c", 1, 1 },
- [QOP_FRAG_X] = { "frag_x", 1, 0 },
- [QOP_FRAG_Y] = { "frag_y", 1, 0 },
[QOP_FRAG_Z] = { "frag_z", 1, 0 },
[QOP_FRAG_W] = { "frag_w", 1, 0 },
- [QOP_FRAG_REV_FLAG] = { "frag_rev_flag", 1, 0 },
- [QOP_TEX_S] = { "tex_s", 0, 2 },
- [QOP_TEX_T] = { "tex_t", 0, 2 },
- [QOP_TEX_R] = { "tex_r", 0, 2 },
- [QOP_TEX_B] = { "tex_b", 0, 2 },
- [QOP_TEX_DIRECT] = { "tex_direct", 0, 2 },
+ [QOP_TEX_S] = { "tex_s", 0, 2, true },
+ [QOP_TEX_T] = { "tex_t", 0, 2, true },
+ [QOP_TEX_R] = { "tex_r", 0, 2, true },
+ [QOP_TEX_B] = { "tex_b", 0, 2, true },
+ [QOP_TEX_DIRECT] = { "tex_direct", 0, 2, true },
[QOP_TEX_RESULT] = { "tex_result", 1, 0, true },
+
+ [QOP_LOAD_IMM] = { "load_imm", 0, 1 },
+
+ [QOP_BRANCH] = { "branch", 0, 0, true },
};
static const char *
bool
qir_has_side_effects(struct vc4_compile *c, struct qinst *inst)
{
+ switch (inst->dst.file) {
+ case QFILE_TLB_Z_WRITE:
+ case QFILE_TLB_COLOR_WRITE:
+ case QFILE_TLB_COLOR_WRITE_MS:
+ case QFILE_TLB_STENCIL_SETUP:
+ return true;
+ default:
+ break;
+ }
+
return qir_op_info[inst->op].has_side_effects;
}
bool
qir_depends_on_flags(struct qinst *inst)
{
- return (inst->cond != QPU_COND_ALWAYS &&
- inst->cond != QPU_COND_NEVER);
+ if (inst->op == QOP_BRANCH) {
+ return inst->cond != QPU_COND_BRANCH_ALWAYS;
+ } else {
+ return (inst->cond != QPU_COND_ALWAYS &&
+ inst->cond != QPU_COND_NEVER);
+ }
}
bool
}
}
+uint8_t
+qir_channels_written(struct qinst *inst)
+{
+ if (qir_is_mul(inst)) {
+ switch (inst->dst.pack) {
+ case QPU_PACK_MUL_NOP:
+ case QPU_PACK_MUL_8888:
+ return 0xf;
+ case QPU_PACK_MUL_8A:
+ return 0x1;
+ case QPU_PACK_MUL_8B:
+ return 0x2;
+ case QPU_PACK_MUL_8C:
+ return 0x4;
+ case QPU_PACK_MUL_8D:
+ return 0x8;
+ }
+ } else {
+ switch (inst->dst.pack) {
+ case QPU_PACK_A_NOP:
+ case QPU_PACK_A_8888:
+ case QPU_PACK_A_8888_SAT:
+ case QPU_PACK_A_32_SAT:
+ return 0xf;
+ case QPU_PACK_A_8A:
+ case QPU_PACK_A_8A_SAT:
+ return 0x1;
+ case QPU_PACK_A_8B:
+ case QPU_PACK_A_8B_SAT:
+ return 0x2;
+ case QPU_PACK_A_8C:
+ case QPU_PACK_A_8C_SAT:
+ return 0x4;
+ case QPU_PACK_A_8D:
+ case QPU_PACK_A_8D_SAT:
+ return 0x8;
+ case QPU_PACK_A_16A:
+ case QPU_PACK_A_16A_SAT:
+ return 0x3;
+ case QPU_PACK_A_16B:
+ case QPU_PACK_A_16B_SAT:
+ return 0xc;
+ }
+ }
+ unreachable("Bad pack field");
+}
+
static void
qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write)
{
[QFILE_TEMP] = "t",
[QFILE_VARY] = "v",
[QFILE_UNIF] = "u",
+ [QFILE_TLB_COLOR_WRITE] = "tlb_c",
+ [QFILE_TLB_COLOR_WRITE_MS] = "tlb_c_ms",
+ [QFILE_TLB_Z_WRITE] = "tlb_z",
+ [QFILE_TLB_STENCIL_SETUP] = "tlb_stencil",
+ [QFILE_FRAG_X] = "frag_x",
+ [QFILE_FRAG_Y] = "frag_y",
+ [QFILE_FRAG_REV_FLAG] = "frag_rev_flag",
};
- if (reg.file == QFILE_NULL) {
+ switch (reg.file) {
+
+ case QFILE_NULL:
fprintf(stderr, "null");
- } else if (reg.file == QFILE_SMALL_IMM) {
+ break;
+
+ case QFILE_LOAD_IMM:
+ fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index));
+ break;
+
+ case QFILE_SMALL_IMM:
if ((int)reg.index >= -16 && (int)reg.index <= 15)
fprintf(stderr, "%d", reg.index);
else
fprintf(stderr, "%f", uif(reg.index));
- } else if (reg.file == QFILE_VPM) {
+ break;
+
+ case QFILE_VPM:
if (write) {
fprintf(stderr, "vpm");
} else {
fprintf(stderr, "vpm%d.%d",
reg.index / 4, reg.index % 4);
}
- } else {
+ break;
+
+ case QFILE_TLB_COLOR_WRITE:
+ case QFILE_TLB_COLOR_WRITE_MS:
+ case QFILE_TLB_Z_WRITE:
+ case QFILE_TLB_STENCIL_SETUP:
+ fprintf(stderr, "%s", files[reg.file]);
+ break;
+
+ default:
fprintf(stderr, "%s%d", files[reg.file], reg.index);
+ break;
}
if (reg.file == QFILE_UNIF &&
void
qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
{
- static const char *conditions[] = {
- [QPU_COND_ALWAYS] = "",
- [QPU_COND_NEVER] = ".never",
- [QPU_COND_ZS] = ".zs",
- [QPU_COND_ZC] = ".zc",
- [QPU_COND_NS] = ".ns",
- [QPU_COND_NC] = ".nc",
- [QPU_COND_CS] = ".cs",
- [QPU_COND_CC] = ".cc",
- };
- fprintf(stderr, "%s%s%s ",
- qir_get_op_name(inst->op),
- conditions[inst->cond],
- inst->sf ? ".sf" : "");
+ fprintf(stderr, "%s", qir_get_op_name(inst->op));
+ if (inst->op == QOP_BRANCH)
+ vc4_qpu_disasm_cond_branch(stderr, inst->cond);
+ else
+ vc4_qpu_disasm_cond(stderr, inst->cond);
+ if (inst->sf)
+ fprintf(stderr, ".sf");
+ fprintf(stderr, " ");
- qir_print_reg(c, inst->dst, true);
- if (inst->dst.pack) {
+ if (inst->op != QOP_BRANCH) {
+ qir_print_reg(c, inst->dst, true);
if (inst->dst.pack) {
- if (qir_is_mul(inst))
- vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
- else
- vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
+ if (inst->dst.pack) {
+ if (qir_is_mul(inst))
+ vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
+ else
+ vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
+ }
}
}
+
for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
fprintf(stderr, ", ");
qir_print_reg(c, inst->src[i], false);
void
qir_dump(struct vc4_compile *c)
{
- list_for_each_entry(struct qinst, inst, &c->instructions, link) {
- qir_dump_inst(c, inst);
- fprintf(stderr, "\n");
+ int ip = 0;
+
+ qir_for_each_block(block, c) {
+ fprintf(stderr, "BLOCK %d:\n", block->index);
+ qir_for_each_inst(inst, block) {
+ if (c->temp_start) {
+ bool first = true;
+
+ for (int i = 0; i < c->num_temps; i++) {
+ if (c->temp_start[i] != ip)
+ continue;
+
+ if (first) {
+ first = false;
+ } else {
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "S%4d", i);
+ }
+
+ if (first)
+ fprintf(stderr, " ");
+ else
+ fprintf(stderr, " ");
+ }
+
+ if (c->temp_end) {
+ bool first = true;
+
+ for (int i = 0; i < c->num_temps; i++) {
+ if (c->temp_end[i] != ip)
+ continue;
+
+ if (first) {
+ first = false;
+ } else {
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "E%4d", i);
+ }
+
+ if (first)
+ fprintf(stderr, " ");
+ else
+ fprintf(stderr, " ");
+ }
+
+ qir_dump_inst(c, inst);
+ fprintf(stderr, "\n");
+ ip++;
+ }
+ if (block->successors[1]) {
+ fprintf(stderr, "-> BLOCK %d, %d\n",
+ block->successors[0]->index,
+ block->successors[1]->index);
+ } else if (block->successors[0]) {
+ fprintf(stderr, "-> BLOCK %d\n",
+ block->successors[0]->index);
+ }
}
}
return inst;
}
-void
+static void
qir_emit(struct vc4_compile *c, struct qinst *inst)
{
+ list_addtail(&inst->link, &c->cur_block->instructions);
+}
+
+/* Updates inst to write to a new temporary, emits it, and notes the def. */
+struct qreg
+qir_emit_def(struct vc4_compile *c, struct qinst *inst)
+{
+ assert(inst->dst.file == QFILE_NULL);
+
+ inst->dst = qir_get_temp(c);
+
if (inst->dst.file == QFILE_TEMP)
c->defs[inst->dst.index] = inst;
- qir_emit_nodef(c, inst);
+ qir_emit(c, inst);
+
+ return inst->dst;
+}
+
+struct qinst *
+qir_emit_nondef(struct vc4_compile *c, struct qinst *inst)
+{
+ if (inst->dst.file == QFILE_TEMP)
+ c->defs[inst->dst.index] = NULL;
+
+ qir_emit(c, inst);
+
+ return inst;
}
bool
qir_reg_equals(struct qreg a, struct qreg b)
{
- return a.file == b.file && a.index == b.index;
+ return a.file == b.file && a.index == b.index && a.pack == b.pack;
+}
+
+struct qblock *
+qir_new_block(struct vc4_compile *c)
+{
+ struct qblock *block = rzalloc(c, struct qblock);
+
+ list_inithead(&block->instructions);
+
+ block->predecessors = _mesa_set_create(block,
+ _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
+ block->index = c->next_block_index++;
+
+ return block;
+}
+
+void
+qir_set_emit_block(struct vc4_compile *c, struct qblock *block)
+{
+ c->cur_block = block;
+ list_addtail(&block->link, &c->blocks);
+}
+
+struct qblock *
+qir_entry_block(struct vc4_compile *c)
+{
+ return list_first_entry(&c->blocks, struct qblock, link);
+}
+
+struct qblock *
+qir_exit_block(struct vc4_compile *c)
+{
+ return list_last_entry(&c->blocks, struct qblock, link);
+}
+
+void
+qir_link_blocks(struct qblock *predecessor, struct qblock *successor)
+{
+ _mesa_set_add(successor->predecessors, predecessor);
+ if (predecessor->successors[0]) {
+ assert(!predecessor->successors[1]);
+ predecessor->successors[1] = successor;
+ } else {
+ predecessor->successors[0] = successor;
+ }
}
struct vc4_compile *
{
struct vc4_compile *c = rzalloc(NULL, struct vc4_compile);
- list_inithead(&c->instructions);
+ list_inithead(&c->blocks);
+ qir_set_emit_block(c, qir_new_block(c));
c->output_position_index = -1;
c->output_color_index = -1;
void
qir_compile_destroy(struct vc4_compile *c)
{
- while (!list_empty(&c->instructions)) {
- struct qinst *qinst =
- (struct qinst *)c->instructions.next;
- qir_remove_instruction(c, qinst);
+ qir_for_each_block(block, c) {
+ while (!list_empty(&block->instructions)) {
+ struct qinst *qinst =
+ list_first_entry(&block->instructions,
+ struct qinst, link);
+ qir_remove_instruction(c, qinst);
+ }
}
ralloc_free(c);
for (int i = 0; i < c->num_uniforms; i++) {
if (c->uniform_contents[i] == contents &&
c->uniform_data[i] == data) {
- return (struct qreg) { QFILE_UNIF, i };
+ return qir_reg(QFILE_UNIF, i);
}
}
uint32_t uniform = c->num_uniforms++;
- struct qreg u = { QFILE_UNIF, uniform };
if (uniform >= c->uniform_array_size) {
c->uniform_array_size = MAX2(MAX2(16, uniform + 1),
c->uniform_contents[uniform] = contents;
c->uniform_data[uniform] = data;
- return u;
+ return qir_reg(QFILE_UNIF, uniform);
}
void
qir_SF(struct vc4_compile *c, struct qreg src)
{
struct qinst *last_inst = NULL;
- if (!list_empty(&c->instructions))
- last_inst = (struct qinst *)c->instructions.prev;
+
+ if (!list_empty(&c->cur_block->instructions))
+ last_inst = (struct qinst *)c->cur_block->instructions.prev;
/* We don't have any way to guess which kind of MOV is implied. */
assert(!src.pack);
if (src.file != QFILE_TEMP ||
!c->defs[src.index] ||
last_inst != c->defs[src.index]) {
- struct qreg null = { QFILE_NULL, 0 };
- last_inst = qir_MOV_dest(c, null, src);
- last_inst = (struct qinst *)c->instructions.prev;
+ last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src);
+ last_inst = (struct qinst *)c->cur_block->instructions.prev;
}
last_inst->sf = true;
}
"QIR opt pass %2d: %s progress\n", \
pass, #func); \
} \
+ qir_validate(c); \
} \
} while (0)
bool progress = false;
OPTPASS(qir_opt_algebraic);
- OPTPASS(qir_opt_cse);
OPTPASS(qir_opt_constant_folding);
OPTPASS(qir_opt_copy_propagation);
+ OPTPASS(qir_opt_peephole_sf);
OPTPASS(qir_opt_dead_code);
OPTPASS(qir_opt_small_immediates);
OPTPASS(qir_opt_vpm);