/** * This just eliminates instructions with null dst so far. */ static void eliminate_dead_code(struct toy_compiler *tc) { struct toy_inst *inst; tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case GEN6_OPCODE_IF: case GEN6_OPCODE_ELSE: case GEN6_OPCODE_ENDIF: case GEN6_OPCODE_WHILE: case GEN6_OPCODE_BREAK: case GEN6_OPCODE_CONT: case GEN6_OPCODE_SEND: case GEN6_OPCODE_SENDC: case GEN6_OPCODE_NOP: /* never eliminated */ break; default: if (tdst_is_null(inst->dst) || !inst->dst.writemask) { /* math is always GEN6_COND_NORMAL */ if ((inst->opcode == GEN6_OPCODE_MATH || inst->cond_modifier == GEN6_COND_NORMAL) && !inst->acc_wr_ctrl) tc_discard_inst(tc, inst); } break; } } }
/** * Compile the shader. */ static bool gs_compile(struct gs_compile_context *gcc) { struct toy_compiler *tc = &gcc->tc; struct ilo_shader *sh = gcc->shader; get_num_prims_static(gcc); if (gcc->is_static) { tc_head(tc); gs_init_vars(gcc); gs_ff_sync(gcc, tdst_d(gcc->vars.tmp), tsrc_imm_d(gcc->static_data.total_prims)); gs_COPY1(tc, gcc->vars.urb_write_header, 0, tsrc_from(tdst_d(gcc->vars.tmp)), 0); if (gcc->write_so) gs_COPY4(tc, gcc->vars.so_index, 0, tsrc_from(tdst_d(gcc->vars.tmp)), 1); tc_tail(tc); } else { tc_fail(tc, "no control flow support"); return false; } if (!gcc->write_vue) gs_discard(gcc); gs_lower_virtual_opcodes(gcc); toy_compiler_legalize_for_ra(tc); toy_compiler_optimize(tc); toy_compiler_allocate_registers(tc, gcc->first_free_grf, gcc->last_free_grf, 1); toy_compiler_legalize_for_asm(tc); if (tc->fail) { ilo_err("failed to legalize GS instructions: %s\n", tc->reason); return false; } if (ilo_debug & ILO_DEBUG_GS) { ilo_printf("legalized instructions:\n"); toy_compiler_dump(tc); ilo_printf("\n"); } sh->kernel = toy_compiler_assemble(tc, &sh->kernel_size); if (!sh->kernel) return false; if (ilo_debug & ILO_DEBUG_GS) { ilo_printf("disassembly:\n"); toy_compiler_disassemble(tc->dev, sh->kernel, sh->kernel_size, false); ilo_printf("\n"); } return true; }
/** * Get the number of (tessellated) primitives generated by this shader. * Return false if that is unknown until runtime. */ static void get_num_prims_static(struct gs_compile_context *gcc) { struct toy_compiler *tc = &gcc->tc; const struct toy_inst *inst; int num_vertices_in_prim = 0, if_depth = 0, do_depth = 0; bool is_static = true; tc_head(tc); while ((inst = tc_next_no_skip(tc)) != NULL) { switch (inst->opcode) { case GEN6_OPCODE_IF: if_depth++; break; case GEN6_OPCODE_ENDIF: if_depth--; break; case TOY_OPCODE_DO: do_depth++; break; case GEN6_OPCODE_WHILE: do_depth--; break; case TOY_OPCODE_EMIT: if (if_depth || do_depth) { is_static = false; } else { gcc->static_data.total_vertices++; num_vertices_in_prim++; if (num_vertices_in_prim >= gcc->out_vue_min_count) gcc->static_data.total_prims++; } break; case TOY_OPCODE_ENDPRIM: if (if_depth || do_depth) { is_static = false; } else { const int vertidx = gcc->static_data.total_vertices - 1; const int idx = vertidx / 32; const int subidx = vertidx % 32; gcc->static_data.last_vertex[idx] |= 1 << subidx; num_vertices_in_prim = 0; } break; default: break; } if (!is_static) break; } gcc->is_static = is_static; }
/** * Dump the instructions added to the compiler. */ void toy_compiler_dump(struct toy_compiler *tc) { struct toy_inst *inst; int pc; pc = 0; tc_head(tc); while ((inst = tc_next_no_skip(tc)) != NULL) { /* we do not generate code for markers */ if (inst->marker) ilo_printf("marker:"); else ilo_printf("%6d:", pc++); tc_dump_inst(tc, inst); } }
static void gs_lower_virtual_opcodes(struct gs_compile_context *gcc) { struct toy_compiler *tc = &gcc->tc; struct toy_inst *inst; tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case TOY_OPCODE_TGSI_IN: case TOY_OPCODE_TGSI_CONST: case TOY_OPCODE_TGSI_SV: case TOY_OPCODE_TGSI_IMM: gs_lower_opcode_tgsi_direct(gcc, inst); break; case TOY_OPCODE_TGSI_INDIRECT_FETCH: case TOY_OPCODE_TGSI_INDIRECT_STORE: /* TODO similar to VS */ tc_fail(tc, "no indirection support"); tc_discard_inst(tc, inst); break; case TOY_OPCODE_TGSI_TEX: case TOY_OPCODE_TGSI_TXB: case TOY_OPCODE_TGSI_TXD: case TOY_OPCODE_TGSI_TXL: case TOY_OPCODE_TGSI_TXP: case TOY_OPCODE_TGSI_TXF: case TOY_OPCODE_TGSI_TXQ: case TOY_OPCODE_TGSI_TXQ_LZ: case TOY_OPCODE_TGSI_TEX2: case TOY_OPCODE_TGSI_TXB2: case TOY_OPCODE_TGSI_TXL2: case TOY_OPCODE_TGSI_SAMPLE: case TOY_OPCODE_TGSI_SAMPLE_I: case TOY_OPCODE_TGSI_SAMPLE_I_MS: case TOY_OPCODE_TGSI_SAMPLE_B: case TOY_OPCODE_TGSI_SAMPLE_C: case TOY_OPCODE_TGSI_SAMPLE_C_LZ: case TOY_OPCODE_TGSI_SAMPLE_D: case TOY_OPCODE_TGSI_SAMPLE_L: case TOY_OPCODE_TGSI_GATHER4: case TOY_OPCODE_TGSI_SVIEWINFO: case TOY_OPCODE_TGSI_SAMPLE_POS: case TOY_OPCODE_TGSI_SAMPLE_INFO: /* TODO similar to VS */ tc_fail(tc, "no sampling support"); tc_discard_inst(tc, inst); break; case TOY_OPCODE_EMIT: gs_lower_opcode_emit(gcc, inst); tc_discard_inst(tc, inst); break; case TOY_OPCODE_ENDPRIM: gs_lower_opcode_endprim(gcc, inst); tc_discard_inst(tc, inst); break; default: break; } } tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case TOY_OPCODE_INV: case TOY_OPCODE_LOG: case TOY_OPCODE_EXP: case TOY_OPCODE_SQRT: case TOY_OPCODE_RSQ: case TOY_OPCODE_SIN: case TOY_OPCODE_COS: case TOY_OPCODE_FDIV: case TOY_OPCODE_POW: case TOY_OPCODE_INT_DIV_QUOTIENT: case TOY_OPCODE_INT_DIV_REMAINDER: toy_compiler_lower_math(tc, inst); break; case TOY_OPCODE_URB_WRITE: toy_compiler_lower_to_send(tc, inst, false, GEN6_SFID_URB); break; default: if (inst->opcode > 127) tc_fail(tc, "unhandled virtual opcode"); break; } } }
static void vs_lower_virtual_opcodes(struct vs_compile_context *vcc) { struct toy_compiler *tc = &vcc->tc; struct toy_inst *inst; tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case TOY_OPCODE_TGSI_IN: case TOY_OPCODE_TGSI_CONST: case TOY_OPCODE_TGSI_SV: case TOY_OPCODE_TGSI_IMM: vs_lower_opcode_tgsi_direct(vcc, inst); break; case TOY_OPCODE_TGSI_INDIRECT_FETCH: case TOY_OPCODE_TGSI_INDIRECT_STORE: vs_lower_opcode_tgsi_indirect(vcc, inst); break; case TOY_OPCODE_TGSI_TEX: case TOY_OPCODE_TGSI_TXB: case TOY_OPCODE_TGSI_TXD: case TOY_OPCODE_TGSI_TXL: case TOY_OPCODE_TGSI_TXP: case TOY_OPCODE_TGSI_TXF: case TOY_OPCODE_TGSI_TXQ: case TOY_OPCODE_TGSI_TXQ_LZ: case TOY_OPCODE_TGSI_TEX2: case TOY_OPCODE_TGSI_TXB2: case TOY_OPCODE_TGSI_TXL2: case TOY_OPCODE_TGSI_SAMPLE: case TOY_OPCODE_TGSI_SAMPLE_I: case TOY_OPCODE_TGSI_SAMPLE_I_MS: case TOY_OPCODE_TGSI_SAMPLE_B: case TOY_OPCODE_TGSI_SAMPLE_C: case TOY_OPCODE_TGSI_SAMPLE_C_LZ: case TOY_OPCODE_TGSI_SAMPLE_D: case TOY_OPCODE_TGSI_SAMPLE_L: case TOY_OPCODE_TGSI_GATHER4: case TOY_OPCODE_TGSI_SVIEWINFO: case TOY_OPCODE_TGSI_SAMPLE_POS: case TOY_OPCODE_TGSI_SAMPLE_INFO: vs_lower_opcode_tgsi_sampling(vcc, inst); break; case TOY_OPCODE_INV: case TOY_OPCODE_LOG: case TOY_OPCODE_EXP: case TOY_OPCODE_SQRT: case TOY_OPCODE_RSQ: case TOY_OPCODE_SIN: case TOY_OPCODE_COS: case TOY_OPCODE_FDIV: case TOY_OPCODE_POW: case TOY_OPCODE_INT_DIV_QUOTIENT: case TOY_OPCODE_INT_DIV_REMAINDER: toy_compiler_lower_math(tc, inst); break; case TOY_OPCODE_URB_WRITE: vs_lower_opcode_urb_write(tc, inst); break; default: if (inst->opcode > 127) tc_fail(tc, "unhandled virtual opcode"); break; } } }
static void fs_lower_virtual_opcodes(struct fs_compile_context *fcc) { struct toy_compiler *tc = &fcc->tc; struct toy_inst *inst; /* lower TGSI's first, as they might be lowered to other virtual opcodes */ tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case TOY_OPCODE_TGSI_IN: case TOY_OPCODE_TGSI_CONST: case TOY_OPCODE_TGSI_SV: case TOY_OPCODE_TGSI_IMM: fs_lower_opcode_tgsi_direct(fcc, inst); break; case TOY_OPCODE_TGSI_INDIRECT_FETCH: case TOY_OPCODE_TGSI_INDIRECT_STORE: fs_lower_opcode_tgsi_indirect(fcc, inst); break; case TOY_OPCODE_TGSI_TEX: case TOY_OPCODE_TGSI_TXB: case TOY_OPCODE_TGSI_TXD: case TOY_OPCODE_TGSI_TXL: case TOY_OPCODE_TGSI_TXP: case TOY_OPCODE_TGSI_TXF: case TOY_OPCODE_TGSI_TXQ: case TOY_OPCODE_TGSI_TXQ_LZ: case TOY_OPCODE_TGSI_TEX2: case TOY_OPCODE_TGSI_TXB2: case TOY_OPCODE_TGSI_TXL2: case TOY_OPCODE_TGSI_SAMPLE: case TOY_OPCODE_TGSI_SAMPLE_I: case TOY_OPCODE_TGSI_SAMPLE_I_MS: case TOY_OPCODE_TGSI_SAMPLE_B: case TOY_OPCODE_TGSI_SAMPLE_C: case TOY_OPCODE_TGSI_SAMPLE_C_LZ: case TOY_OPCODE_TGSI_SAMPLE_D: case TOY_OPCODE_TGSI_SAMPLE_L: case TOY_OPCODE_TGSI_GATHER4: case TOY_OPCODE_TGSI_SVIEWINFO: case TOY_OPCODE_TGSI_SAMPLE_POS: case TOY_OPCODE_TGSI_SAMPLE_INFO: fs_lower_opcode_tgsi_sampling(fcc, inst); break; } } tc_head(tc); while ((inst = tc_next(tc)) != NULL) { switch (inst->opcode) { case TOY_OPCODE_INV: case TOY_OPCODE_LOG: case TOY_OPCODE_EXP: case TOY_OPCODE_SQRT: case TOY_OPCODE_RSQ: case TOY_OPCODE_SIN: case TOY_OPCODE_COS: case TOY_OPCODE_FDIV: case TOY_OPCODE_POW: case TOY_OPCODE_INT_DIV_QUOTIENT: case TOY_OPCODE_INT_DIV_REMAINDER: toy_compiler_lower_math(tc, inst); break; case TOY_OPCODE_DDX: case TOY_OPCODE_DDY: fs_lower_opcode_derivative(tc, inst); break; case TOY_OPCODE_FB_WRITE: fs_lower_opcode_fb_write(tc, inst); break; case TOY_OPCODE_KIL: fs_lower_opcode_kil(tc, inst); break; default: if (inst->opcode > 127) tc_fail(tc, "unhandled virtual opcode"); break; } } }