tgsi_parse_free(&parse);
}
-/**
- * Collect information about the arrays of a given register file.
- *
- * @param tokens TGSI shader
- * @param file the register file to scan through
- * @param max_array_id number of entries in @p arrays; should be equal to the
- * highest array id, i.e. tgsi_shader_info::array_max[file].
- * @param arrays info for array of each ID will be written to arrays[ID - 1].
- */
-void
-tgsi_scan_arrays(const struct tgsi_token *tokens,
- unsigned file,
- unsigned max_array_id,
- struct tgsi_array_info *arrays)
-{
- struct tgsi_parse_context parse;
-
- if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
- debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
- return;
- }
-
- memset(arrays, 0, sizeof(arrays[0]) * max_array_id);
-
- while (!tgsi_parse_end_of_tokens(&parse)) {
- struct tgsi_full_instruction *inst;
-
- tgsi_parse_token(&parse);
-
- if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {
- struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
-
- if (decl->Declaration.Array && decl->Declaration.File == file &&
- decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {
- struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];
- assert(!array->declared);
- array->declared = true;
- array->range = decl->Range;
- }
- }
-
- if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
- continue;
-
- inst = &parse.FullToken.FullInstruction;
- for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
- const struct tgsi_full_dst_register *dst = &inst->Dst[i];
- if (dst->Register.File != file)
- continue;
-
- if (dst->Register.Indirect) {
- if (dst->Indirect.ArrayID > 0 &&
- dst->Indirect.ArrayID <= max_array_id) {
- arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;
- } else {
- /* Indirect writes without an ArrayID can write anywhere. */
- for (unsigned j = 0; j < max_array_id; ++j)
- arrays[j].writemask |= dst->Register.WriteMask;
- }
- } else {
- /* Check whether the write falls into any of the arrays anyway. */
- for (unsigned j = 0; j < max_array_id; ++j) {
- struct tgsi_array_info *array = &arrays[j];
- if (array->declared &&
- dst->Register.Index >= array->range.First &&
- dst->Register.Index <= array->range.Last)
- array->writemask |= dst->Register.WriteMask;
- }
- }
- }
- }
-
- tgsi_parse_free(&parse);
-
- return;
-}
-
-static void
-check_no_subroutines(const struct tgsi_full_instruction *inst)
-{
- switch (inst->Instruction.Opcode) {
- case TGSI_OPCODE_BGNSUB:
- case TGSI_OPCODE_ENDSUB:
- case TGSI_OPCODE_CAL:
- unreachable("subroutines unhandled");
- }
-}
-
-static unsigned
-get_inst_tessfactor_writemask(const struct tgsi_shader_info *info,
- const struct tgsi_full_instruction *inst)
-{
- unsigned writemask = 0;
-
- for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
- const struct tgsi_full_dst_register *dst = &inst->Dst[i];
-
- if (dst->Register.File == TGSI_FILE_OUTPUT &&
- !dst->Register.Indirect) {
- unsigned name = info->output_semantic_name[dst->Register.Index];
-
- if (name == TGSI_SEMANTIC_TESSINNER)
- writemask |= dst->Register.WriteMask;
- else if (name == TGSI_SEMANTIC_TESSOUTER)
- writemask |= dst->Register.WriteMask << 4;
- }
- }
- return writemask;
-}
-
-static unsigned
-get_block_tessfactor_writemask(const struct tgsi_shader_info *info,
- struct tgsi_parse_context *parse,
- unsigned end_opcode)
-{
- struct tgsi_full_instruction *inst;
- unsigned writemask = 0;
-
- tgsi_parse_token(parse);
- assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
- inst = &parse->FullToken.FullInstruction;
- check_no_subroutines(inst);
-
- while (inst->Instruction.Opcode != end_opcode) {
-
- /* Recursively process nested blocks. */
- switch (inst->Instruction.Opcode) {
- case TGSI_OPCODE_IF:
- case TGSI_OPCODE_UIF:
- writemask |=
- get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF);
- break;
-
- case TGSI_OPCODE_BGNLOOP:
- writemask |=
- get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
- break;
-
- case TGSI_OPCODE_BARRIER:
- unreachable("nested BARRIER is illegal");
- break;
-
- default:
- writemask |= get_inst_tessfactor_writemask(info, inst);
- }
-
- tgsi_parse_token(parse);
- assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
- inst = &parse->FullToken.FullInstruction;
- check_no_subroutines(inst);
- }
-
- return writemask;
-}
-
-static void
-get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info,
- struct tgsi_parse_context *parse,
- unsigned *upper_block_tf_writemask,
- unsigned *cond_block_tf_writemask)
-{
- struct tgsi_full_instruction *inst;
- unsigned then_tessfactor_writemask = 0;
- unsigned else_tessfactor_writemask = 0;
- unsigned writemask;
- bool is_then = true;
-
- tgsi_parse_token(parse);
- assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
- inst = &parse->FullToken.FullInstruction;
- check_no_subroutines(inst);
-
- while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF) {
-
- switch (inst->Instruction.Opcode) {
- case TGSI_OPCODE_ELSE:
- is_then = false;
- break;
-
- /* Recursively process nested blocks. */
- case TGSI_OPCODE_IF:
- case TGSI_OPCODE_UIF:
- get_if_block_tessfactor_writemask(info, parse,
- is_then ? &then_tessfactor_writemask :
- &else_tessfactor_writemask,
- cond_block_tf_writemask);
- break;
-
- case TGSI_OPCODE_BGNLOOP:
- *cond_block_tf_writemask |=
- get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
- break;
-
- case TGSI_OPCODE_BARRIER:
- unreachable("nested BARRIER is illegal");
- break;
- default:
- /* Process an instruction in the current block. */
- writemask = get_inst_tessfactor_writemask(info, inst);
-
- if (writemask) {
- if (is_then)
- then_tessfactor_writemask |= writemask;
- else
- else_tessfactor_writemask |= writemask;
- }
- }
-
- tgsi_parse_token(parse);
- assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
- inst = &parse->FullToken.FullInstruction;
- check_no_subroutines(inst);
- }
-
- if (then_tessfactor_writemask || else_tessfactor_writemask) {
- /* If both statements write the same tess factor channels,
- * we can say that the upper block writes them too. */
- *upper_block_tf_writemask |= then_tessfactor_writemask &
- else_tessfactor_writemask;
- *cond_block_tf_writemask |= then_tessfactor_writemask |
- else_tessfactor_writemask;
- }
-}