diff options
author | Eric Anholt <[email protected]> | 2017-02-03 10:24:14 -0800 |
---|---|---|
committer | Eric Anholt <[email protected]> | 2017-10-10 11:42:04 -0700 |
commit | ade416d02369cc0942d53ad3cce601d66344f9c3 (patch) | |
tree | f9824bfb74dc9ef33b78dc67295768fdd07a513a /src/broadcom/compiler/vir.c | |
parent | f71364f29787d0f822474ed970c5f28bede49abb (diff) |
broadcom: Add VC5 NIR compiler.
This is a pretty straightforward fork of VC4's NIR compiler to VC5. The
condition codes, registers, and I/O have all changed, making the backend
hard to share, though their heritage is still recognizable.
v2: Move to src/broadcom/compiler to match intel's layout, rename more
"vc5" to "v3d", rename QIR to VIR ("V3D IR") to avoid symbol conflicts
with vc4, use new v3d_debug header, add compiler init/free functions,
do texture swizzling in NIR to allow optimization.
Diffstat (limited to 'src/broadcom/compiler/vir.c')
-rw-r--r-- | src/broadcom/compiler/vir.c | 907 |
1 files changed, 907 insertions, 0 deletions
diff --git a/src/broadcom/compiler/vir.c b/src/broadcom/compiler/vir.c new file mode 100644 index 00000000000..35df757a208 --- /dev/null +++ b/src/broadcom/compiler/vir.c @@ -0,0 +1,907 @@ +/* + * Copyright © 2016-2017 Broadcom + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "v3d_compiler.h" + +int +vir_get_non_sideband_nsrc(struct qinst *inst) +{ + switch (inst->qpu.type) { + case V3D_QPU_INSTR_TYPE_BRANCH: + return 0; + case V3D_QPU_INSTR_TYPE_ALU: + if (inst->qpu.alu.add.op != V3D_QPU_A_NOP) + return v3d_qpu_add_op_num_src(inst->qpu.alu.add.op); + else + return v3d_qpu_mul_op_num_src(inst->qpu.alu.mul.op); + } + + return 0; +} + +int +vir_get_nsrc(struct qinst *inst) +{ + int nsrc = vir_get_non_sideband_nsrc(inst); + + if (vir_has_implicit_uniform(inst)) + nsrc++; + + return nsrc; +} + +bool +vir_has_implicit_uniform(struct qinst *inst) +{ + switch (inst->qpu.type) { + case V3D_QPU_INSTR_TYPE_BRANCH: + return true; + case V3D_QPU_INSTR_TYPE_ALU: + switch (inst->dst.file) { + case QFILE_TLBU: + return true; + default: + return inst->has_implicit_uniform; + } + } + return false; +} + +/* The sideband uniform for textures gets stored after the normal ALU + * arguments. + */ +int +vir_get_implicit_uniform_src(struct qinst *inst) +{ + return vir_get_nsrc(inst) - 1; +} + +/** + * Returns whether the instruction has any side effects that must be + * preserved. + */ +bool +vir_has_side_effects(struct v3d_compile *c, struct qinst *inst) +{ + switch (inst->qpu.type) { + case V3D_QPU_INSTR_TYPE_BRANCH: + return true; + case V3D_QPU_INSTR_TYPE_ALU: + switch (inst->qpu.alu.add.op) { + case V3D_QPU_A_SETREVF: + case V3D_QPU_A_SETMSF: + case V3D_QPU_A_VPMSETUP: + return true; + default: + break; + } + + switch (inst->qpu.alu.mul.op) { + case V3D_QPU_M_MULTOP: + return true; + default: + break; + } + } + + if (inst->qpu.sig.ldtmu) + return true; + + return false; +} + +bool +vir_is_float_input(struct qinst *inst) +{ + /* XXX: More instrs */ + switch (inst->qpu.type) { + case V3D_QPU_INSTR_TYPE_BRANCH: + return false; + case V3D_QPU_INSTR_TYPE_ALU: + switch (inst->qpu.alu.add.op) { + case V3D_QPU_A_FADD: + case V3D_QPU_A_FSUB: + case V3D_QPU_A_FMIN: + case V3D_QPU_A_FMAX: + case V3D_QPU_A_FTOIN: + return true; + default: + break; + } + + switch (inst->qpu.alu.mul.op) { + case V3D_QPU_M_FMOV: + case V3D_QPU_M_VFMUL: + case V3D_QPU_M_FMUL: + return true; + default: + break; + } + } + + return false; +} + +bool +vir_is_raw_mov(struct qinst *inst) +{ + if (inst->qpu.type != V3D_QPU_INSTR_TYPE_ALU || + (inst->qpu.alu.mul.op != V3D_QPU_M_FMOV && + inst->qpu.alu.mul.op != V3D_QPU_M_MOV)) { + return false; + } + + if (inst->qpu.alu.add.output_pack != V3D_QPU_PACK_NONE || + inst->qpu.alu.mul.output_pack != V3D_QPU_PACK_NONE) { + return false; + } + + if (inst->qpu.flags.ac != V3D_QPU_COND_NONE || + inst->qpu.flags.mc != V3D_QPU_COND_NONE) + return false; + + return true; +} + +bool +vir_is_add(struct qinst *inst) +{ + return (inst->qpu.type == V3D_QPU_INSTR_TYPE_ALU && + inst->qpu.alu.add.op != V3D_QPU_A_NOP); +} + +bool +vir_is_mul(struct qinst *inst) +{ + return (inst->qpu.type == V3D_QPU_INSTR_TYPE_ALU && + inst->qpu.alu.mul.op != V3D_QPU_M_NOP); +} + +bool +vir_is_tex(struct qinst *inst) +{ + if (inst->dst.file == QFILE_MAGIC) + return v3d_qpu_magic_waddr_is_tmu(inst->dst.index); + + return false; +} + +bool +vir_depends_on_flags(struct qinst *inst) +{ + if (inst->qpu.type == V3D_QPU_INSTR_TYPE_BRANCH) { + return (inst->qpu.branch.cond != V3D_QPU_BRANCH_COND_ALWAYS); + } else { + return (inst->qpu.flags.ac != V3D_QPU_COND_NONE && + inst->qpu.flags.mc != V3D_QPU_COND_NONE); + } +} + +bool +vir_writes_r3(struct qinst *inst) +{ + for (int i = 0; i < vir_get_nsrc(inst); i++) { + switch (inst->src[i].file) { + case QFILE_VARY: + case QFILE_VPM: + return true; + default: + break; + } + } + + return false; +} + +bool +vir_writes_r4(struct qinst *inst) +{ + switch (inst->dst.file) { + case QFILE_MAGIC: + switch (inst->dst.index) { + case V3D_QPU_WADDR_RECIP: + case V3D_QPU_WADDR_RSQRT: + case V3D_QPU_WADDR_EXP: + case V3D_QPU_WADDR_LOG: + case V3D_QPU_WADDR_SIN: + return true; + } + break; + default: + break; + } + + if (inst->qpu.sig.ldtmu) + return true; + + return false; +} + +void +vir_set_unpack(struct qinst *inst, int src, + enum v3d_qpu_input_unpack unpack) +{ + assert(src == 0 || src == 1); + + if (vir_is_add(inst)) { + if (src == 0) + inst->qpu.alu.add.a_unpack = unpack; + else + inst->qpu.alu.add.b_unpack = unpack; + } else { + assert(vir_is_mul(inst)); + if (src == 0) + inst->qpu.alu.mul.a_unpack = unpack; + else + inst->qpu.alu.mul.b_unpack = unpack; + } +} + +void +vir_set_cond(struct qinst *inst, enum v3d_qpu_cond cond) +{ + if (vir_is_add(inst)) { + inst->qpu.flags.ac = cond; + } else { + assert(vir_is_mul(inst)); + inst->qpu.flags.mc = cond; + } +} + +void +vir_set_pf(struct qinst *inst, enum v3d_qpu_pf pf) +{ + if (vir_is_add(inst)) { + inst->qpu.flags.apf = pf; + } else { + assert(vir_is_mul(inst)); + inst->qpu.flags.mpf = pf; + } +} + +#if 0 +uint8_t +vir_channels_written(struct qinst *inst) +{ + if (vir_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"); +} +#endif + +struct qreg +vir_get_temp(struct v3d_compile *c) +{ + struct qreg reg; + + reg.file = QFILE_TEMP; + reg.index = c->num_temps++; + + if (c->num_temps > c->defs_array_size) { + uint32_t old_size = c->defs_array_size; + c->defs_array_size = MAX2(old_size * 2, 16); + c->defs = reralloc(c, c->defs, struct qinst *, + c->defs_array_size); + memset(&c->defs[old_size], 0, + sizeof(c->defs[0]) * (c->defs_array_size - old_size)); + } + + return reg; +} + +struct qinst * +vir_add_inst(enum v3d_qpu_add_op op, struct qreg dst, struct qreg src0, struct qreg src1) +{ + struct qinst *inst = calloc(1, sizeof(*inst)); + + inst->qpu = v3d_qpu_nop(); + inst->qpu.alu.add.op = op; + + inst->dst = dst; + inst->src[0] = src0; + inst->src[1] = src1; + inst->uniform = ~0; + + return inst; +} + +struct qinst * +vir_mul_inst(enum v3d_qpu_mul_op op, struct qreg dst, struct qreg src0, struct qreg src1) +{ + struct qinst *inst = calloc(1, sizeof(*inst)); + + inst->qpu = v3d_qpu_nop(); + inst->qpu.alu.mul.op = op; + + inst->dst = dst; + inst->src[0] = src0; + inst->src[1] = src1; + inst->uniform = ~0; + + return inst; +} + +struct qinst * +vir_branch_inst(enum v3d_qpu_branch_cond cond, struct qreg src) +{ + struct qinst *inst = calloc(1, sizeof(*inst)); + + inst->qpu = v3d_qpu_nop(); + inst->qpu.type = V3D_QPU_INSTR_TYPE_BRANCH; + inst->qpu.branch.cond = cond; + inst->qpu.branch.msfign = V3D_QPU_MSFIGN_NONE; + inst->qpu.branch.bdi = V3D_QPU_BRANCH_DEST_REL; + inst->qpu.branch.ub = true; + inst->qpu.branch.bdu = V3D_QPU_BRANCH_DEST_REL; + + inst->dst = vir_reg(QFILE_NULL, 0); + inst->src[0] = src; + inst->uniform = ~0; + + return inst; +} + +static void +vir_emit(struct v3d_compile *c, struct qinst *inst) +{ + list_addtail(&inst->link, &c->cur_block->instructions); + + if (inst->dst.file == QFILE_MAGIC && + inst->dst.index == V3D_QPU_WADDR_VPM) + c->num_vpm_writes++; +} + +/* Updates inst to write to a new temporary, emits it, and notes the def. */ +struct qreg +vir_emit_def(struct v3d_compile *c, struct qinst *inst) +{ + assert(inst->dst.file == QFILE_NULL); + + inst->dst = vir_get_temp(c); + + if (inst->dst.file == QFILE_TEMP) + c->defs[inst->dst.index] = inst; + + vir_emit(c, inst); + + return inst->dst; +} + +struct qinst * +vir_emit_nondef(struct v3d_compile *c, struct qinst *inst) +{ + if (inst->dst.file == QFILE_TEMP) + c->defs[inst->dst.index] = NULL; + + vir_emit(c, inst); + + return inst; +} + +struct qblock * +vir_new_block(struct v3d_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 +vir_set_emit_block(struct v3d_compile *c, struct qblock *block) +{ + c->cur_block = block; + list_addtail(&block->link, &c->blocks); +} + +struct qblock * +vir_entry_block(struct v3d_compile *c) +{ + return list_first_entry(&c->blocks, struct qblock, link); +} + +struct qblock * +vir_exit_block(struct v3d_compile *c) +{ + return list_last_entry(&c->blocks, struct qblock, link); +} + +void +vir_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; + } +} + +const struct v3d_compiler * +v3d_compiler_init(const struct v3d_device_info *devinfo) +{ + struct v3d_compiler *compiler = rzalloc(NULL, struct v3d_compiler); + if (!compiler) + return NULL; + + compiler->devinfo = devinfo; + + if (!vir_init_reg_sets(compiler)) { + ralloc_free(compiler); + return NULL; + } + + return compiler; +} + +void +v3d_compiler_free(const struct v3d_compiler *compiler) +{ + ralloc_free((void *)compiler); +} + +static struct v3d_compile * +vir_compile_init(const struct v3d_compiler *compiler, + struct v3d_key *key, + nir_shader *s, + int program_id, int variant_id) +{ + struct v3d_compile *c = rzalloc(NULL, struct v3d_compile); + + c->compiler = compiler; + c->devinfo = compiler->devinfo; + c->key = key; + c->program_id = program_id; + c->variant_id = variant_id; + + s = nir_shader_clone(c, s); + c->s = s; + + list_inithead(&c->blocks); + vir_set_emit_block(c, vir_new_block(c)); + + c->output_position_index = -1; + c->output_point_size_index = -1; + c->output_sample_mask_index = -1; + + c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer, + _mesa_key_pointer_equal); + + return c; +} + +static void +v3d_lower_nir(struct v3d_compile *c) +{ + struct nir_lower_tex_options tex_options = { + .lower_rect = false, /* XXX */ + .lower_txp = ~0, + /* Apply swizzles to all samplers. */ + .swizzle_result = ~0, + }; + + /* Lower the format swizzle and (for 32-bit returns) + * ARB_texture_swizzle-style swizzle. + */ + for (int i = 0; i < ARRAY_SIZE(c->key->tex); i++) { + for (int j = 0; j < 4; j++) + tex_options.swizzles[i][j] = c->key->tex[i].swizzle[j]; + } + + NIR_PASS_V(c->s, nir_lower_tex, &tex_options); +} + +static void +v3d_lower_nir_late(struct v3d_compile *c) +{ + NIR_PASS_V(c->s, v3d_nir_lower_io, c); + NIR_PASS_V(c->s, nir_lower_idiv); +} + +static void +v3d_set_prog_data_uniforms(struct v3d_compile *c, + struct v3d_prog_data *prog_data) +{ + int count = c->num_uniforms; + struct v3d_uniform_list *ulist = &prog_data->uniforms; + + ulist->count = count; + ulist->data = ralloc_array(prog_data, uint32_t, count); + memcpy(ulist->data, c->uniform_data, + count * sizeof(*ulist->data)); + ulist->contents = ralloc_array(prog_data, enum quniform_contents, count); + memcpy(ulist->contents, c->uniform_contents, + count * sizeof(*ulist->contents)); +} + +/* Copy the compiler UBO range state to the compiled shader, dropping out + * arrays that were never referenced by an indirect load. + * + * (Note that QIR dead code elimination of an array access still leaves that + * array alive, though) + */ +static void +v3d_set_prog_data_ubo(struct v3d_compile *c, + struct v3d_prog_data *prog_data) +{ + if (!c->num_ubo_ranges) + return; + + prog_data->num_ubo_ranges = 0; + prog_data->ubo_ranges = ralloc_array(prog_data, struct v3d_ubo_range, + c->num_ubo_ranges); + for (int i = 0; i < c->num_ubo_ranges; i++) { + if (!c->ubo_range_used[i]) + continue; + + struct v3d_ubo_range *range = &c->ubo_ranges[i]; + prog_data->ubo_ranges[prog_data->num_ubo_ranges++] = *range; + prog_data->ubo_size += range->size; + } + + if (prog_data->ubo_size) { + if (V3D_DEBUG & V3D_DEBUG_SHADERDB) { + fprintf(stderr, "SHADER-DB: %s prog %d/%d: %d UBO uniforms\n", + vir_get_stage_name(c), + c->program_id, c->variant_id, + prog_data->ubo_size / 4); + } + } +} + +static void +v3d_set_prog_data(struct v3d_compile *c, + struct v3d_prog_data *prog_data) +{ + v3d_set_prog_data_uniforms(c, prog_data); + v3d_set_prog_data_ubo(c, prog_data); +} + +static uint64_t * +v3d_return_qpu_insts(struct v3d_compile *c, uint32_t *final_assembly_size) +{ + *final_assembly_size = c->qpu_inst_count * sizeof(uint64_t); + + uint64_t *qpu_insts = malloc(*final_assembly_size); + if (!qpu_insts) + return NULL; + + memcpy(qpu_insts, c->qpu_insts, *final_assembly_size); + + vir_compile_destroy(c); + + return qpu_insts; +} + +uint64_t *v3d_compile_vs(const struct v3d_compiler *compiler, + struct v3d_vs_key *key, + struct v3d_vs_prog_data *prog_data, + nir_shader *s, + int program_id, int variant_id, + uint32_t *final_assembly_size) +{ + struct v3d_compile *c = vir_compile_init(compiler, &key->base, s, + program_id, variant_id); + + c->vs_key = key; + + v3d_lower_nir(c); + + if (key->clamp_color) + NIR_PASS_V(c->s, nir_lower_clamp_color_outputs); + + if (key->base.ucp_enables) { + NIR_PASS_V(c->s, nir_lower_clip_vs, key->base.ucp_enables); + NIR_PASS_V(c->s, nir_lower_io_to_scalar, + nir_var_shader_out); + } + + /* Note: VS output scalarizing must happen after nir_lower_clip_vs. */ + NIR_PASS_V(c->s, nir_lower_io_to_scalar, nir_var_shader_out); + + v3d_lower_nir_late(c); + v3d_optimize_nir(c->s); + NIR_PASS_V(c->s, nir_convert_from_ssa, true); + + v3d_nir_to_vir(c); + + v3d_set_prog_data(c, &prog_data->base); + + prog_data->base.num_inputs = c->num_inputs; + + /* The vertex data gets format converted by the VPM so that + * each attribute channel takes up a VPM column. Precompute + * the sizes for the shader record. + */ + for (int i = 0; i < ARRAY_SIZE(prog_data->vattr_sizes); i++) { + prog_data->vattr_sizes[i] = c->vattr_sizes[i]; + prog_data->vpm_input_size += c->vattr_sizes[i]; + } + + /* Input/output segment size are in 8x32-bit multiples. */ + prog_data->vpm_input_size = align(prog_data->vpm_input_size, 8) / 8; + prog_data->vpm_output_size = align(c->num_vpm_writes, 8) / 8; + + prog_data->uses_vid = (s->info.system_values_read & + (1ull << SYSTEM_VALUE_VERTEX_ID)); + prog_data->uses_iid = (s->info.system_values_read & + (1ull << SYSTEM_VALUE_INSTANCE_ID)); + + return v3d_return_qpu_insts(c, final_assembly_size); +} + +static void +v3d_set_fs_prog_data_inputs(struct v3d_compile *c, + struct v3d_fs_prog_data *prog_data) +{ + prog_data->base.num_inputs = c->num_inputs; + memcpy(prog_data->input_slots, c->input_slots, + c->num_inputs * sizeof(*c->input_slots)); + + for (int i = 0; i < c->num_inputs; i++) { + struct v3d_varying_slot v3d_slot = c->input_slots[i]; + uint8_t slot = v3d_slot_get_slot(v3d_slot); + + if (slot == VARYING_SLOT_COL0 || + slot == VARYING_SLOT_COL1 || + slot == VARYING_SLOT_BFC0 || + slot == VARYING_SLOT_BFC1) { + BITSET_SET(prog_data->color_inputs, i); + } + + if (BITSET_TEST(c->flat_shade_flags, i)) + BITSET_SET(prog_data->flat_shade_flags, i); + } +} + +uint64_t *v3d_compile_fs(const struct v3d_compiler *compiler, + struct v3d_fs_key *key, + struct v3d_fs_prog_data *prog_data, + nir_shader *s, + int program_id, int variant_id, + uint32_t *final_assembly_size) +{ + struct v3d_compile *c = vir_compile_init(compiler, &key->base, s, + program_id, variant_id); + + c->fs_key = key; + + v3d_lower_nir(c); + + if (key->light_twoside) + NIR_PASS_V(c->s, nir_lower_two_sided_color); + + if (key->clamp_color) + NIR_PASS_V(c->s, nir_lower_clamp_color_outputs); + + if (key->alpha_test) { + NIR_PASS_V(c->s, nir_lower_alpha_test, key->alpha_test_func, + false); + } + + if (key->base.ucp_enables) + NIR_PASS_V(c->s, nir_lower_clip_fs, key->base.ucp_enables); + + /* Note: FS input scalarizing must happen after + * nir_lower_two_sided_color, which only handles a vec4 at a time. + */ + NIR_PASS_V(c->s, nir_lower_io_to_scalar, nir_var_shader_in); + + v3d_lower_nir_late(c); + v3d_optimize_nir(c->s); + NIR_PASS_V(c->s, nir_convert_from_ssa, true); + + v3d_nir_to_vir(c); + + v3d_set_prog_data(c, &prog_data->base); + v3d_set_fs_prog_data_inputs(c, prog_data); + if (c->s->info.outputs_written & (1 << FRAG_RESULT_DEPTH)) + prog_data->writes_z = true; + + return v3d_return_qpu_insts(c, final_assembly_size); +} + +void +vir_remove_instruction(struct v3d_compile *c, struct qinst *qinst) +{ + if (qinst->dst.file == QFILE_TEMP) + c->defs[qinst->dst.index] = NULL; + + list_del(&qinst->link); + free(qinst); +} + +struct qreg +vir_follow_movs(struct v3d_compile *c, struct qreg reg) +{ + /* XXX + int pack = reg.pack; + + while (reg.file == QFILE_TEMP && + c->defs[reg.index] && + (c->defs[reg.index]->op == QOP_MOV || + c->defs[reg.index]->op == QOP_FMOV) && + !c->defs[reg.index]->dst.pack && + !c->defs[reg.index]->src[0].pack) { + reg = c->defs[reg.index]->src[0]; + } + + reg.pack = pack; + */ + return reg; +} + +void +vir_compile_destroy(struct v3d_compile *c) +{ + vir_for_each_block(block, c) { + while (!list_empty(&block->instructions)) { + struct qinst *qinst = + list_first_entry(&block->instructions, + struct qinst, link); + vir_remove_instruction(c, qinst); + } + } + + ralloc_free(c); +} + +struct qreg +vir_uniform(struct v3d_compile *c, + enum quniform_contents contents, + uint32_t data) +{ + for (int i = 0; i < c->num_uniforms; i++) { + if (c->uniform_contents[i] == contents && + c->uniform_data[i] == data) { + return vir_reg(QFILE_UNIF, i); + } + } + + uint32_t uniform = c->num_uniforms++; + + if (uniform >= c->uniform_array_size) { + c->uniform_array_size = MAX2(MAX2(16, uniform + 1), + c->uniform_array_size * 2); + + c->uniform_data = reralloc(c, c->uniform_data, + uint32_t, + c->uniform_array_size); + c->uniform_contents = reralloc(c, c->uniform_contents, + enum quniform_contents, + c->uniform_array_size); + } + + c->uniform_contents[uniform] = contents; + c->uniform_data[uniform] = data; + + return vir_reg(QFILE_UNIF, uniform); +} + +void +vir_PF(struct v3d_compile *c, struct qreg src, enum v3d_qpu_pf pf) +{ + struct qinst *last_inst = NULL; + + if (!list_empty(&c->cur_block->instructions)) + last_inst = (struct qinst *)c->cur_block->instructions.prev; + + if (src.file != QFILE_TEMP || + !c->defs[src.index] || + last_inst != c->defs[src.index]) { + /* XXX: Make the MOV be the appropriate type */ + last_inst = vir_MOV_dest(c, vir_reg(QFILE_NULL, 0), src); + last_inst = (struct qinst *)c->cur_block->instructions.prev; + } + + vir_set_pf(last_inst, pf); +} + +#define OPTPASS(func) \ + do { \ + bool stage_progress = func(c); \ + if (stage_progress) { \ + progress = true; \ + if (print_opt_debug) { \ + fprintf(stderr, \ + "VIR opt pass %2d: %s progress\n", \ + pass, #func); \ + } \ + /*XXX vir_validate(c);*/ \ + } \ + } while (0) + +void +vir_optimize(struct v3d_compile *c) +{ + bool print_opt_debug = false; + int pass = 1; + + while (true) { + bool progress = false; + + OPTPASS(vir_opt_copy_propagate); + OPTPASS(vir_opt_dead_code); + + if (!progress) + break; + + pass++; + } +} + +const char * +vir_get_stage_name(struct v3d_compile *c) +{ + if (c->vs_key && c->vs_key->is_coord) + return "MESA_SHADER_COORD"; + else + return gl_shader_stage_name(c->s->stage); +} |