X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fvc4%2Fvc4_qir.c;h=71f06aebfa04503eb88bae47c42283badda87455;hb=3a9e2d608563d6d305c63039396644f3b976a55d;hp=526e3a179aafc91a31f8e7dfb469a979667ca6ab;hpb=8f2af4763a60c5ea5f64829321ae97bbfa51a4ce;p=mesa.git diff --git a/src/gallium/drivers/vc4/vc4_qir.c b/src/gallium/drivers/vc4/vc4_qir.c index 526e3a179aa..71f06aebfa0 100644 --- a/src/gallium/drivers/vc4/vc4_qir.c +++ b/src/gallium/drivers/vc4/vc4_qir.c @@ -58,6 +58,7 @@ static const struct qir_op_info qir_op_info[] = { [QOP_ASR] = { "asr", 1, 2 }, [QOP_SHL] = { "shl", 1, 2 }, [QOP_MIN] = { "min", 1, 2 }, + [QOP_MIN_NOIMM] = { "min_noimm", 1, 2 }, [QOP_MAX] = { "max", 1, 2 }, [QOP_AND] = { "and", 1, 2 }, [QOP_OR] = { "or", 1, 2 }, @@ -75,14 +76,18 @@ static const struct qir_op_info qir_op_info[] = { [QOP_FRAG_Z] = { "frag_z", 1, 0 }, [QOP_FRAG_W] = { "frag_w", 1, 0 }, - [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_THRSW] = { "thrsw", 0, 0, true }, + [QOP_LOAD_IMM] = { "load_imm", 0, 1 }, + [QOP_LOAD_IMM_U2] = { "load_imm_u2", 0, 1 }, + [QOP_LOAD_IMM_I2] = { "load_imm_i2", 0, 1 }, + + [QOP_ROT_MUL] = { "rot_mul", 0, 2 }, + + [QOP_BRANCH] = { "branch", 0, 0, true }, + [QOP_UNIFORMS_RESET] = { "uniforms_reset", 0, 2, true }, }; static const char * @@ -95,12 +100,35 @@ qir_get_op_name(enum qop qop) } int -qir_get_op_nsrc(enum qop qop) +qir_get_non_sideband_nsrc(struct qinst *inst) { - if (qop < ARRAY_SIZE(qir_op_info) && qir_op_info[qop].name) - return qir_op_info[qop].nsrc; - else - abort(); + assert(qir_op_info[inst->op].name); + return qir_op_info[inst->op].nsrc; +} + +int +qir_get_nsrc(struct qinst *inst) +{ + assert(qir_op_info[inst->op].name); + + int nsrc = qir_get_non_sideband_nsrc(inst); + + /* Normal (non-direct) texture coordinate writes also implicitly load + * a uniform for the texture parameters. + */ + if (qir_is_tex(inst) && inst->dst.file != QFILE_TEX_S_DIRECT) + nsrc++; + + return nsrc; +} + +/* The sideband uniform for textures gets stored after the normal ALU + * arguments. + */ +int +qir_get_tex_uniform_src(struct qinst *inst) +{ + return qir_get_nsrc(inst) - 1; } /** @@ -115,6 +143,11 @@ qir_has_side_effects(struct vc4_compile *c, struct qinst *inst) case QFILE_TLB_COLOR_WRITE: case QFILE_TLB_COLOR_WRITE_MS: case QFILE_TLB_STENCIL_SETUP: + case QFILE_TEX_S_DIRECT: + case QFILE_TEX_S: + case QFILE_TEX_T: + case QFILE_TEX_R: + case QFILE_TEX_B: return true; default: break; @@ -131,7 +164,7 @@ qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst) * point/line coordinates reads, because they're generated by * fixed-function hardware. */ - for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) { + for (int i = 0; i < qir_get_nsrc(inst); i++) { if (inst->src[i].file == QFILE_VARY && c->input_slots[inst->src[i].index].slot == 0xff) { return true; @@ -147,6 +180,17 @@ qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst) return false; } +bool +qir_has_uniform_read(struct qinst *inst) +{ + for (int i = 0; i < qir_get_nsrc(inst); i++) { + if (inst->src[i].file == QFILE_UNIF) + return true; + } + + return false; +} + bool qir_is_mul(struct qinst *inst) { @@ -159,6 +203,7 @@ qir_is_mul(struct qinst *inst) case QOP_V8MAX: case QOP_V8ADDS: case QOP_V8SUBS: + case QOP_ROT_MUL: return true; default: return false; @@ -198,14 +243,41 @@ qir_is_raw_mov(struct qinst *inst) bool qir_is_tex(struct qinst *inst) { - return inst->op >= QOP_TEX_S && inst->op <= QOP_TEX_DIRECT; + switch (inst->dst.file) { + case QFILE_TEX_S_DIRECT: + case QFILE_TEX_S: + case QFILE_TEX_T: + case QFILE_TEX_R: + case QFILE_TEX_B: + return true; + default: + return false; + } +} + +bool +qir_has_implicit_tex_uniform(struct qinst *inst) +{ + switch (inst->dst.file) { + case QFILE_TEX_S: + case QFILE_TEX_T: + case QFILE_TEX_R: + case QFILE_TEX_B: + return true; + default: + return false; + } } 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 @@ -224,13 +296,104 @@ qir_writes_r4(struct qinst *inst) } } +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"); +} + +char * +qir_describe_uniform(enum quniform_contents contents, uint32_t data, + const uint32_t *uniforms) +{ + static const char *quniform_names[] = { + [QUNIFORM_VIEWPORT_X_SCALE] = "vp_x_scale", + [QUNIFORM_VIEWPORT_Y_SCALE] = "vp_y_scale", + [QUNIFORM_VIEWPORT_Z_OFFSET] = "vp_z_offset", + [QUNIFORM_VIEWPORT_Z_SCALE] = "vp_z_scale", + [QUNIFORM_TEXTURE_CONFIG_P0] = "tex_p0", + [QUNIFORM_TEXTURE_CONFIG_P1] = "tex_p1", + [QUNIFORM_TEXTURE_CONFIG_P2] = "tex_p2", + [QUNIFORM_TEXTURE_FIRST_LEVEL] = "tex_first_level", + }; + + switch (contents) { + case QUNIFORM_CONSTANT: + return ralloc_asprintf(NULL, "0x%08x / %f", data, uif(data)); + case QUNIFORM_UNIFORM: + if (uniforms) { + uint32_t unif = uniforms[data]; + return ralloc_asprintf(NULL, "unif[%d] = 0x%08x / %f", + data, unif, uif(unif)); + } else { + return ralloc_asprintf(NULL, "unif[%d]", data); + } + + case QUNIFORM_TEXTURE_CONFIG_P0: + case QUNIFORM_TEXTURE_CONFIG_P1: + case QUNIFORM_TEXTURE_CONFIG_P2: + case QUNIFORM_TEXTURE_FIRST_LEVEL: + return ralloc_asprintf(NULL, "%s[%d]", + quniform_names[contents], data); + + default: + if (contents < ARRAY_SIZE(quniform_names) && + quniform_names[contents]) { + return ralloc_asprintf(NULL, "%s", + quniform_names[contents]); + } else { + return ralloc_asprintf(NULL, "??? %d", contents); + } + } +} + static void qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write) { static const char *files[] = { [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", @@ -238,6 +401,12 @@ qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write) [QFILE_FRAG_X] = "frag_x", [QFILE_FRAG_Y] = "frag_y", [QFILE_FRAG_REV_FLAG] = "frag_rev_flag", + [QFILE_QPU_ELEMENT] = "elem", + [QFILE_TEX_S_DIRECT] = "tex_s_direct", + [QFILE_TEX_S] = "tex_s", + [QFILE_TEX_T] = "tex_t", + [QFILE_TEX_R] = "tex_r", + [QFILE_TEX_B] = "tex_b", }; switch (reg.file) { @@ -270,19 +439,26 @@ qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write) case QFILE_TLB_COLOR_WRITE_MS: case QFILE_TLB_Z_WRITE: case QFILE_TLB_STENCIL_SETUP: + case QFILE_TEX_S_DIRECT: + case QFILE_TEX_S: + case QFILE_TEX_T: + case QFILE_TEX_R: + case QFILE_TEX_B: fprintf(stderr, "%s", files[reg.file]); break; - default: - fprintf(stderr, "%s%d", files[reg.file], reg.index); + case QFILE_UNIF: { + char *desc = qir_describe_uniform(c->uniform_contents[reg.index], + c->uniform_data[reg.index], + NULL); + fprintf(stderr, "u%d (%s)", reg.index, desc); + ralloc_free(desc); break; } - if (reg.file == QFILE_UNIF && - c->uniform_contents[reg.index] == QUNIFORM_CONSTANT) { - fprintf(stderr, " (0x%08x / %f)", - c->uniform_data[reg.index], - uif(c->uniform_data[reg.index])); + default: + fprintf(stderr, "%s%d", files[reg.file], reg.index); + break; } } @@ -290,21 +466,27 @@ void qir_dump_inst(struct vc4_compile *c, struct qinst *inst) { fprintf(stderr, "%s", qir_get_op_name(inst->op)); - vc4_qpu_disasm_cond(stderr, inst->cond); + 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++) { + + for (int i = 0; i < qir_get_nsrc(inst); i++) { fprintf(stderr, ", "); qir_print_reg(c, inst->src[i], false); vc4_qpu_disasm_unpack(stderr, inst->src[i].pack); @@ -314,9 +496,70 @@ qir_dump_inst(struct vc4_compile *c, struct qinst *inst) 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; + int pressure = 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; + + fprintf(stderr, "%3d ", pressure); + + 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); + pressure++; + } + + 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); + pressure--; + } + + 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); + } } } @@ -348,7 +591,6 @@ qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1) inst->op = op; inst->dst = dst; - inst->src = calloc(2, sizeof(inst->src[0])); inst->src[0] = src0; inst->src[1] = src1; inst->cond = QPU_COND_ALWAYS; @@ -356,33 +598,37 @@ qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1) return inst; } -struct qinst * -qir_inst4(enum qop op, struct qreg dst, - struct qreg a, - struct qreg b, - struct qreg c, - struct qreg d) +static void +qir_emit(struct vc4_compile *c, struct qinst *inst) { - struct qinst *inst = CALLOC_STRUCT(qinst); + list_addtail(&inst->link, &c->cur_block->instructions); +} - inst->op = op; - inst->dst = dst; - inst->src = calloc(4, sizeof(*inst->src)); - inst->src[0] = a; - inst->src[1] = b; - inst->src[2] = c; - inst->src[3] = d; +/* 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); - return inst; + inst->dst = qir_get_temp(c); + + if (inst->dst.file == QFILE_TEMP) + c->defs[inst->dst.index] = inst; + + qir_emit(c, inst); + + return inst->dst; } -void -qir_emit(struct vc4_compile *c, struct qinst *inst) +struct qinst * +qir_emit_nondef(struct vc4_compile *c, struct qinst *inst) { if (inst->dst.file == QFILE_TEMP) - c->defs[inst->dst.index] = inst; + c->defs[inst->dst.index] = NULL; - qir_emit_nodef(c, inst); + qir_emit(c, inst); + + return inst; } bool @@ -391,12 +637,62 @@ qir_reg_equals(struct qreg a, struct qreg b) 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); + list_inithead(&block->qpu_inst_list); + + 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 * qir_compile_init(void) { 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->last_top_block = c->cur_block; c->output_position_index = -1; c->output_color_index = -1; @@ -416,7 +712,6 @@ qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst) c->defs[qinst->dst.index] = NULL; list_del(&qinst->link); - free(qinst->src); free(qinst); } @@ -442,10 +737,13 @@ qir_follow_movs(struct vc4_compile *c, struct qreg reg) 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); @@ -499,8 +797,9 @@ 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); @@ -509,7 +808,7 @@ qir_SF(struct vc4_compile *c, struct qreg src) !c->defs[src.index] || last_inst != c->defs[src.index]) { last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src); - last_inst = (struct qinst *)c->instructions.prev; + last_inst = (struct qinst *)c->cur_block->instructions.prev; } last_inst->sf = true; } @@ -544,6 +843,7 @@ qir_optimize(struct vc4_compile *c) OPTPASS(qir_opt_dead_code); OPTPASS(qir_opt_small_immediates); OPTPASS(qir_opt_vpm); + OPTPASS(qir_opt_coalesce_ff_writes); if (!progress) break;