Path: blob/21.2-virgl/src/gallium/auxiliary/tgsi/tgsi_scan.c
4565 views
/**************************************************************************1*2* Copyright 2008 VMware, Inc.3* All Rights Reserved.4* Copyright 2008 VMware, Inc. All rights Reserved.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the8* "Software"), to deal in the Software without restriction, including9* without limitation the rights to use, copy, modify, merge, publish,10* distribute, sub license, and/or sell copies of the Software, and to11* permit persons to whom the Software is furnished to do so, subject to12* the following conditions:13*14* The above copyright notice and this permission notice (including the15* next paragraph) shall be included in all copies or substantial portions16* of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS19* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF20* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.21* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR22* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,23* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE24* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.25*26**************************************************************************/2728/**29* TGSI program scan utility.30* Used to determine which registers and instructions are used by a shader.31*32* Authors: Brian Paul33*/343536#include "util/u_debug.h"37#include "util/u_math.h"38#include "util/u_memory.h"39#include "util/u_prim.h"40#include "tgsi/tgsi_info.h"41#include "tgsi/tgsi_parse.h"42#include "tgsi/tgsi_util.h"43#include "tgsi/tgsi_scan.h"444546static bool47is_memory_file(unsigned file)48{49return file == TGSI_FILE_SAMPLER ||50file == TGSI_FILE_SAMPLER_VIEW ||51file == TGSI_FILE_IMAGE ||52file == TGSI_FILE_BUFFER ||53file == TGSI_FILE_HW_ATOMIC;54}555657static bool58is_mem_query_inst(enum tgsi_opcode opcode)59{60return opcode == TGSI_OPCODE_RESQ ||61opcode == TGSI_OPCODE_TXQ ||62opcode == TGSI_OPCODE_TXQS ||63opcode == TGSI_OPCODE_LODQ;64}6566/**67* Is the opcode a "true" texture instruction which samples from a68* texture map?69*/70static bool71is_texture_inst(enum tgsi_opcode opcode)72{73return (!is_mem_query_inst(opcode) &&74tgsi_get_opcode_info(opcode)->is_tex);75}767778/**79* Is the opcode an instruction which computes a derivative explicitly or80* implicitly?81*/82static bool83computes_derivative(enum tgsi_opcode opcode)84{85if (tgsi_get_opcode_info(opcode)->is_tex) {86return opcode != TGSI_OPCODE_TG4 &&87opcode != TGSI_OPCODE_TXD &&88opcode != TGSI_OPCODE_TXF &&89opcode != TGSI_OPCODE_TXF_LZ &&90opcode != TGSI_OPCODE_TEX_LZ &&91opcode != TGSI_OPCODE_TXL &&92opcode != TGSI_OPCODE_TXL2 &&93opcode != TGSI_OPCODE_TXQ &&94opcode != TGSI_OPCODE_TXQS;95}9697return opcode == TGSI_OPCODE_DDX || opcode == TGSI_OPCODE_DDX_FINE ||98opcode == TGSI_OPCODE_DDY || opcode == TGSI_OPCODE_DDY_FINE ||99opcode == TGSI_OPCODE_SAMPLE ||100opcode == TGSI_OPCODE_SAMPLE_B ||101opcode == TGSI_OPCODE_SAMPLE_C;102}103104105static void106scan_src_operand(struct tgsi_shader_info *info,107const struct tgsi_full_instruction *fullinst,108const struct tgsi_full_src_register *src,109unsigned src_index,110unsigned usage_mask_after_swizzle,111bool is_interp_instruction,112bool *is_mem_inst)113{114int ind = src->Register.Index;115116if (info->processor == PIPE_SHADER_COMPUTE &&117src->Register.File == TGSI_FILE_SYSTEM_VALUE) {118unsigned name, mask;119120name = info->system_value_semantic_name[src->Register.Index];121122switch (name) {123case TGSI_SEMANTIC_THREAD_ID:124case TGSI_SEMANTIC_BLOCK_ID:125mask = usage_mask_after_swizzle & TGSI_WRITEMASK_XYZ;126while (mask) {127unsigned i = u_bit_scan(&mask);128129if (name == TGSI_SEMANTIC_THREAD_ID)130info->uses_thread_id[i] = true;131else132info->uses_block_id[i] = true;133}134break;135case TGSI_SEMANTIC_BLOCK_SIZE:136/* The block size is translated to IMM with a fixed block size. */137if (info->properties[TGSI_PROPERTY_CS_FIXED_BLOCK_WIDTH] == 0)138info->uses_block_size = true;139break;140case TGSI_SEMANTIC_GRID_SIZE:141info->uses_grid_size = true;142break;143}144}145146/* Mark which inputs are effectively used */147if (src->Register.File == TGSI_FILE_INPUT) {148if (src->Register.Indirect) {149for (ind = 0; ind < info->num_inputs; ++ind) {150info->input_usage_mask[ind] |= usage_mask_after_swizzle;151}152} else {153assert(ind >= 0);154assert(ind < PIPE_MAX_SHADER_INPUTS);155info->input_usage_mask[ind] |= usage_mask_after_swizzle;156}157158if (info->processor == PIPE_SHADER_FRAGMENT) {159unsigned name, index, input;160161if (src->Register.Indirect && src->Indirect.ArrayID)162input = info->input_array_first[src->Indirect.ArrayID];163else164input = src->Register.Index;165166name = info->input_semantic_name[input];167index = info->input_semantic_index[input];168169if (name == TGSI_SEMANTIC_POSITION &&170usage_mask_after_swizzle & TGSI_WRITEMASK_Z)171info->reads_z = true;172173if (name == TGSI_SEMANTIC_COLOR)174info->colors_read |= usage_mask_after_swizzle << (index * 4);175176/* Process only interpolated varyings. Don't include POSITION.177* Don't include integer varyings, because they are not178* interpolated. Don't process inputs interpolated by INTERP179* opcodes. Those are tracked separately.180*/181if ((!is_interp_instruction || src_index != 0) &&182(name == TGSI_SEMANTIC_GENERIC ||183name == TGSI_SEMANTIC_TEXCOORD ||184name == TGSI_SEMANTIC_COLOR ||185name == TGSI_SEMANTIC_BCOLOR ||186name == TGSI_SEMANTIC_FOG ||187name == TGSI_SEMANTIC_CLIPDIST)) {188switch (info->input_interpolate[input]) {189case TGSI_INTERPOLATE_COLOR:190case TGSI_INTERPOLATE_PERSPECTIVE:191switch (info->input_interpolate_loc[input]) {192case TGSI_INTERPOLATE_LOC_CENTER:193info->uses_persp_center = TRUE;194break;195case TGSI_INTERPOLATE_LOC_CENTROID:196info->uses_persp_centroid = TRUE;197break;198case TGSI_INTERPOLATE_LOC_SAMPLE:199info->uses_persp_sample = TRUE;200break;201}202break;203case TGSI_INTERPOLATE_LINEAR:204switch (info->input_interpolate_loc[input]) {205case TGSI_INTERPOLATE_LOC_CENTER:206info->uses_linear_center = TRUE;207break;208case TGSI_INTERPOLATE_LOC_CENTROID:209info->uses_linear_centroid = TRUE;210break;211case TGSI_INTERPOLATE_LOC_SAMPLE:212info->uses_linear_sample = TRUE;213break;214}215break;216/* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */217}218}219}220}221222if (info->processor == PIPE_SHADER_TESS_CTRL &&223src->Register.File == TGSI_FILE_OUTPUT) {224unsigned input;225226if (src->Register.Indirect && src->Indirect.ArrayID)227input = info->output_array_first[src->Indirect.ArrayID];228else229input = src->Register.Index;230231switch (info->output_semantic_name[input]) {232case TGSI_SEMANTIC_PATCH:233info->reads_perpatch_outputs = true;234break;235case TGSI_SEMANTIC_TESSINNER:236case TGSI_SEMANTIC_TESSOUTER:237info->reads_tessfactor_outputs = true;238break;239default:240info->reads_pervertex_outputs = true;241}242}243244/* check for indirect register reads */245if (src->Register.Indirect) {246info->indirect_files |= (1 << src->Register.File);247info->indirect_files_read |= (1 << src->Register.File);248249/* record indirect constant buffer indexing */250if (src->Register.File == TGSI_FILE_CONSTANT) {251if (src->Register.Dimension) {252if (src->Dimension.Indirect)253info->const_buffers_indirect = info->const_buffers_declared;254else255info->const_buffers_indirect |= 1u << src->Dimension.Index;256} else {257info->const_buffers_indirect |= 1;258}259}260}261262if (src->Register.Dimension && src->Dimension.Indirect)263info->dim_indirect_files |= 1u << src->Register.File;264265/* Texture samplers */266if (src->Register.File == TGSI_FILE_SAMPLER) {267const unsigned index = src->Register.Index;268269assert(fullinst->Instruction.Texture);270assert(index < PIPE_MAX_SAMPLERS);271272if (is_texture_inst(fullinst->Instruction.Opcode)) {273const unsigned target = fullinst->Texture.Texture;274assert(target < TGSI_TEXTURE_UNKNOWN);275/* for texture instructions, check that the texture instruction276* target matches the previous sampler view declaration (if there277* was one.)278*/279if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {280/* probably no sampler view declaration */281info->sampler_targets[index] = target;282} else {283/* Make sure the texture instruction's sampler/target info284* agrees with the sampler view declaration.285*/286assert(info->sampler_targets[index] == target);287}288}289}290291if (is_memory_file(src->Register.File) &&292!is_mem_query_inst(fullinst->Instruction.Opcode)) {293*is_mem_inst = true;294295if (src->Register.File == TGSI_FILE_IMAGE &&296(fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||297fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {298if (src->Register.Indirect)299info->msaa_images_declared = info->images_declared;300else301info->msaa_images_declared |= 1 << src->Register.Index;302}303304if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {305info->writes_memory = TRUE;306307if (src->Register.File == TGSI_FILE_IMAGE) {308if (src->Register.Indirect)309info->images_atomic = info->images_declared;310else311info->images_atomic |= 1 << src->Register.Index;312} else if (src->Register.File == TGSI_FILE_BUFFER) {313if (src->Register.Indirect)314info->shader_buffers_atomic = info->shader_buffers_declared;315else316info->shader_buffers_atomic |= 1 << src->Register.Index;317}318} else {319if (src->Register.File == TGSI_FILE_IMAGE) {320if (src->Register.Indirect)321info->images_load = info->images_declared;322else323info->images_load |= 1 << src->Register.Index;324} else if (src->Register.File == TGSI_FILE_BUFFER) {325if (src->Register.Indirect)326info->shader_buffers_load = info->shader_buffers_declared;327else328info->shader_buffers_load |= 1 << src->Register.Index;329}330}331}332}333334335static void336scan_instruction(struct tgsi_shader_info *info,337const struct tgsi_full_instruction *fullinst,338unsigned *current_depth)339{340unsigned i;341bool is_mem_inst = false;342bool is_interp_instruction = false;343unsigned sampler_src;344345assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);346info->opcode_count[fullinst->Instruction.Opcode]++;347348switch (fullinst->Instruction.Opcode) {349case TGSI_OPCODE_IF:350case TGSI_OPCODE_UIF:351case TGSI_OPCODE_BGNLOOP:352(*current_depth)++;353info->max_depth = MAX2(info->max_depth, *current_depth);354break;355case TGSI_OPCODE_ENDIF:356case TGSI_OPCODE_ENDLOOP:357(*current_depth)--;358break;359case TGSI_OPCODE_TEX:360case TGSI_OPCODE_TEX_LZ:361case TGSI_OPCODE_TXB:362case TGSI_OPCODE_TXD:363case TGSI_OPCODE_TXL:364case TGSI_OPCODE_TXP:365case TGSI_OPCODE_TXQ:366case TGSI_OPCODE_TXQS:367case TGSI_OPCODE_TXF:368case TGSI_OPCODE_TXF_LZ:369case TGSI_OPCODE_TEX2:370case TGSI_OPCODE_TXB2:371case TGSI_OPCODE_TXL2:372case TGSI_OPCODE_TG4:373case TGSI_OPCODE_LODQ:374sampler_src = fullinst->Instruction.NumSrcRegs - 1;375if (fullinst->Src[sampler_src].Register.File != TGSI_FILE_SAMPLER)376info->uses_bindless_samplers = true;377break;378case TGSI_OPCODE_RESQ:379if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File))380info->uses_bindless_images = true;381break;382case TGSI_OPCODE_LOAD:383if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) {384info->uses_bindless_images = true;385386if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER)387info->uses_bindless_buffer_load = true;388else389info->uses_bindless_image_load = true;390}391break;392case TGSI_OPCODE_ATOMUADD:393case TGSI_OPCODE_ATOMXCHG:394case TGSI_OPCODE_ATOMCAS:395case TGSI_OPCODE_ATOMAND:396case TGSI_OPCODE_ATOMOR:397case TGSI_OPCODE_ATOMXOR:398case TGSI_OPCODE_ATOMUMIN:399case TGSI_OPCODE_ATOMUMAX:400case TGSI_OPCODE_ATOMIMIN:401case TGSI_OPCODE_ATOMIMAX:402case TGSI_OPCODE_ATOMFADD:403case TGSI_OPCODE_ATOMINC_WRAP:404case TGSI_OPCODE_ATOMDEC_WRAP:405if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) {406info->uses_bindless_images = true;407408if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER)409info->uses_bindless_buffer_atomic = true;410else411info->uses_bindless_image_atomic = true;412}413break;414case TGSI_OPCODE_STORE:415if (tgsi_is_bindless_image_file(fullinst->Dst[0].Register.File)) {416info->uses_bindless_images = true;417418if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER)419info->uses_bindless_buffer_store = true;420else421info->uses_bindless_image_store = true;422}423break;424case TGSI_OPCODE_FBFETCH:425info->uses_fbfetch = true;426break;427default:428break;429}430431if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID ||432fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||433fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {434const struct tgsi_full_src_register *src0 = &fullinst->Src[0];435unsigned input;436437is_interp_instruction = true;438439if (src0->Register.Indirect && src0->Indirect.ArrayID)440input = info->input_array_first[src0->Indirect.ArrayID];441else442input = src0->Register.Index;443444/* For the INTERP opcodes, the interpolation is always445* PERSPECTIVE unless LINEAR is specified.446*/447switch (info->input_interpolate[input]) {448case TGSI_INTERPOLATE_COLOR:449case TGSI_INTERPOLATE_CONSTANT:450case TGSI_INTERPOLATE_PERSPECTIVE:451switch (fullinst->Instruction.Opcode) {452case TGSI_OPCODE_INTERP_CENTROID:453info->uses_persp_opcode_interp_centroid = TRUE;454break;455case TGSI_OPCODE_INTERP_OFFSET:456info->uses_persp_opcode_interp_offset = TRUE;457break;458case TGSI_OPCODE_INTERP_SAMPLE:459info->uses_persp_opcode_interp_sample = TRUE;460break;461}462break;463464case TGSI_INTERPOLATE_LINEAR:465switch (fullinst->Instruction.Opcode) {466case TGSI_OPCODE_INTERP_CENTROID:467info->uses_linear_opcode_interp_centroid = TRUE;468break;469case TGSI_OPCODE_INTERP_OFFSET:470info->uses_linear_opcode_interp_offset = TRUE;471break;472case TGSI_OPCODE_INTERP_SAMPLE:473info->uses_linear_opcode_interp_sample = TRUE;474break;475}476break;477}478}479480if ((fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D &&481fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) ||482fullinst->Instruction.Opcode == TGSI_OPCODE_DFMA ||483fullinst->Instruction.Opcode == TGSI_OPCODE_DDIV ||484fullinst->Instruction.Opcode == TGSI_OPCODE_D2U64 ||485fullinst->Instruction.Opcode == TGSI_OPCODE_D2I64 ||486fullinst->Instruction.Opcode == TGSI_OPCODE_U642D ||487fullinst->Instruction.Opcode == TGSI_OPCODE_I642D)488info->uses_doubles = TRUE;489490for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {491scan_src_operand(info, fullinst, &fullinst->Src[i], i,492tgsi_util_get_inst_usage_mask(fullinst, i),493is_interp_instruction, &is_mem_inst);494495if (fullinst->Src[i].Register.Indirect) {496struct tgsi_full_src_register src = {{0}};497498src.Register.File = fullinst->Src[i].Indirect.File;499src.Register.Index = fullinst->Src[i].Indirect.Index;500501scan_src_operand(info, fullinst, &src, -1,5021 << fullinst->Src[i].Indirect.Swizzle,503false, NULL);504}505506if (fullinst->Src[i].Register.Dimension &&507fullinst->Src[i].Dimension.Indirect) {508struct tgsi_full_src_register src = {{0}};509510src.Register.File = fullinst->Src[i].DimIndirect.File;511src.Register.Index = fullinst->Src[i].DimIndirect.Index;512513scan_src_operand(info, fullinst, &src, -1,5141 << fullinst->Src[i].DimIndirect.Swizzle,515false, NULL);516}517}518519if (fullinst->Instruction.Texture) {520for (i = 0; i < fullinst->Texture.NumOffsets; i++) {521struct tgsi_full_src_register src = {{0}};522523src.Register.File = fullinst->TexOffsets[i].File;524src.Register.Index = fullinst->TexOffsets[i].Index;525526/* The usage mask is suboptimal but should be safe. */527scan_src_operand(info, fullinst, &src, -1,528(1 << fullinst->TexOffsets[i].SwizzleX) |529(1 << fullinst->TexOffsets[i].SwizzleY) |530(1 << fullinst->TexOffsets[i].SwizzleZ),531false, &is_mem_inst);532}533}534535/* check for indirect register writes */536for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {537const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];538539if (dst->Register.Indirect) {540struct tgsi_full_src_register src = {{0}};541542src.Register.File = dst->Indirect.File;543src.Register.Index = dst->Indirect.Index;544545scan_src_operand(info, fullinst, &src, -1,5461 << dst->Indirect.Swizzle, false, NULL);547548info->indirect_files |= (1 << dst->Register.File);549info->indirect_files_written |= (1 << dst->Register.File);550}551552if (dst->Register.Dimension && dst->Dimension.Indirect) {553struct tgsi_full_src_register src = {{0}};554555src.Register.File = dst->DimIndirect.File;556src.Register.Index = dst->DimIndirect.Index;557558scan_src_operand(info, fullinst, &src, -1,5591 << dst->DimIndirect.Swizzle, false, NULL);560561info->dim_indirect_files |= 1u << dst->Register.File;562}563564if (is_memory_file(dst->Register.File)) {565assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);566567is_mem_inst = true;568info->writes_memory = TRUE;569570if (dst->Register.File == TGSI_FILE_IMAGE) {571if (fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||572fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA) {573if (dst->Register.Indirect)574info->msaa_images_declared = info->images_declared;575else576info->msaa_images_declared |= 1 << dst->Register.Index;577}578579if (dst->Register.Indirect)580info->images_store = info->images_declared;581else582info->images_store |= 1 << dst->Register.Index;583} else if (dst->Register.File == TGSI_FILE_BUFFER) {584if (dst->Register.Indirect)585info->shader_buffers_store = info->shader_buffers_declared;586else587info->shader_buffers_store |= 1 << dst->Register.Index;588}589}590}591592if (is_mem_inst)593info->num_memory_instructions++;594595if (computes_derivative(fullinst->Instruction.Opcode))596info->uses_derivatives = true;597598info->num_instructions++;599}600601602static void603scan_declaration(struct tgsi_shader_info *info,604const struct tgsi_full_declaration *fulldecl)605{606const uint file = fulldecl->Declaration.File;607const unsigned procType = info->processor;608uint reg;609610if (fulldecl->Declaration.Array) {611unsigned array_id = fulldecl->Array.ArrayID;612613switch (file) {614case TGSI_FILE_INPUT:615assert(array_id < ARRAY_SIZE(info->input_array_first));616info->input_array_first[array_id] = fulldecl->Range.First;617info->input_array_last[array_id] = fulldecl->Range.Last;618break;619case TGSI_FILE_OUTPUT:620assert(array_id < ARRAY_SIZE(info->output_array_first));621info->output_array_first[array_id] = fulldecl->Range.First;622info->output_array_last[array_id] = fulldecl->Range.Last;623break;624}625info->array_max[file] = MAX2(info->array_max[file], array_id);626}627628for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {629unsigned semName = fulldecl->Semantic.Name;630unsigned semIndex = fulldecl->Semantic.Index +631(reg - fulldecl->Range.First);632int buffer;633unsigned index, target, type;634635/*636* only first 32 regs will appear in this bitfield, if larger637* bits will wrap around.638*/639info->file_mask[file] |= (1u << (reg & 31));640info->file_count[file]++;641info->file_max[file] = MAX2(info->file_max[file], (int)reg);642643switch (file) {644case TGSI_FILE_CONSTANT:645buffer = 0;646647if (fulldecl->Declaration.Dimension)648buffer = fulldecl->Dim.Index2D;649650info->const_file_max[buffer] =651MAX2(info->const_file_max[buffer], (int)reg);652info->const_buffers_declared |= 1u << buffer;653break;654655case TGSI_FILE_IMAGE:656info->images_declared |= 1u << reg;657if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)658info->images_buffers |= 1 << reg;659break;660661case TGSI_FILE_BUFFER:662info->shader_buffers_declared |= 1u << reg;663break;664665case TGSI_FILE_INPUT:666info->input_semantic_name[reg] = (ubyte) semName;667info->input_semantic_index[reg] = (ubyte) semIndex;668info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;669info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;670info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;671672/* Vertex shaders can have inputs with holes between them. */673info->num_inputs = MAX2(info->num_inputs, reg + 1);674675switch (semName) {676case TGSI_SEMANTIC_PRIMID:677info->uses_primid = true;678break;679case TGSI_SEMANTIC_POSITION:680info->reads_position = true;681break;682case TGSI_SEMANTIC_FACE:683info->uses_frontface = true;684break;685}686break;687688case TGSI_FILE_SYSTEM_VALUE:689index = fulldecl->Range.First;690691info->system_value_semantic_name[index] = semName;692info->num_system_values = MAX2(info->num_system_values, index + 1);693694switch (semName) {695case TGSI_SEMANTIC_INSTANCEID:696info->uses_instanceid = TRUE;697break;698case TGSI_SEMANTIC_VERTEXID:699info->uses_vertexid = TRUE;700break;701case TGSI_SEMANTIC_VERTEXID_NOBASE:702info->uses_vertexid_nobase = TRUE;703break;704case TGSI_SEMANTIC_BASEVERTEX:705info->uses_basevertex = TRUE;706break;707case TGSI_SEMANTIC_DRAWID:708info->uses_drawid = TRUE;709break;710case TGSI_SEMANTIC_PRIMID:711info->uses_primid = TRUE;712break;713case TGSI_SEMANTIC_INVOCATIONID:714info->uses_invocationid = TRUE;715break;716case TGSI_SEMANTIC_POSITION:717info->reads_position = TRUE;718break;719case TGSI_SEMANTIC_FACE:720info->uses_frontface = TRUE;721break;722case TGSI_SEMANTIC_SAMPLEMASK:723info->reads_samplemask = TRUE;724break;725case TGSI_SEMANTIC_TESSINNER:726case TGSI_SEMANTIC_TESSOUTER:727info->reads_tess_factors = true;728break;729}730break;731732case TGSI_FILE_OUTPUT:733info->output_semantic_name[reg] = (ubyte) semName;734info->output_semantic_index[reg] = (ubyte) semIndex;735info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;736info->num_outputs = MAX2(info->num_outputs, reg + 1);737738if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {739info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX;740info->num_stream_output_components[fulldecl->Semantic.StreamX]++;741}742if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {743info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2;744info->num_stream_output_components[fulldecl->Semantic.StreamY]++;745}746if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {747info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4;748info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;749}750if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {751info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6;752info->num_stream_output_components[fulldecl->Semantic.StreamW]++;753}754755switch (semName) {756case TGSI_SEMANTIC_PRIMID:757info->writes_primid = true;758break;759case TGSI_SEMANTIC_VIEWPORT_INDEX:760info->writes_viewport_index = true;761break;762case TGSI_SEMANTIC_LAYER:763info->writes_layer = true;764break;765case TGSI_SEMANTIC_PSIZE:766info->writes_psize = true;767break;768case TGSI_SEMANTIC_CLIPVERTEX:769info->writes_clipvertex = true;770break;771case TGSI_SEMANTIC_COLOR:772info->colors_written |= 1 << semIndex;773break;774case TGSI_SEMANTIC_STENCIL:775info->writes_stencil = true;776break;777case TGSI_SEMANTIC_SAMPLEMASK:778info->writes_samplemask = true;779break;780case TGSI_SEMANTIC_EDGEFLAG:781info->writes_edgeflag = true;782break;783case TGSI_SEMANTIC_POSITION:784if (procType == PIPE_SHADER_FRAGMENT)785info->writes_z = true;786else787info->writes_position = true;788break;789}790break;791792case TGSI_FILE_SAMPLER:793STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);794info->samplers_declared |= 1u << reg;795break;796797case TGSI_FILE_SAMPLER_VIEW:798target = fulldecl->SamplerView.Resource;799type = fulldecl->SamplerView.ReturnTypeX;800801assert(target < TGSI_TEXTURE_UNKNOWN);802if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {803/* Save sampler target for this sampler index */804info->sampler_targets[reg] = target;805info->sampler_type[reg] = type;806} else {807/* if previously declared, make sure targets agree */808assert(info->sampler_targets[reg] == target);809assert(info->sampler_type[reg] == type);810}811break;812}813}814}815816817static void818scan_immediate(struct tgsi_shader_info *info)819{820uint reg = info->immediate_count++;821uint file = TGSI_FILE_IMMEDIATE;822823info->file_mask[file] |= (1 << reg);824info->file_count[file]++;825info->file_max[file] = MAX2(info->file_max[file], (int)reg);826}827828829static void830scan_property(struct tgsi_shader_info *info,831const struct tgsi_full_property *fullprop)832{833unsigned name = fullprop->Property.PropertyName;834unsigned value = fullprop->u[0].Data;835836assert(name < ARRAY_SIZE(info->properties));837info->properties[name] = value;838839switch (name) {840case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:841info->num_written_clipdistance = value;842info->clipdist_writemask |= (1 << value) - 1;843break;844case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:845info->num_written_culldistance = value;846info->culldist_writemask |= (1 << value) - 1;847break;848}849}850851852/**853* Scan the given TGSI shader to collect information such as number of854* registers used, special instructions used, etc.855* \return info the result of the scan856*/857void858tgsi_scan_shader(const struct tgsi_token *tokens,859struct tgsi_shader_info *info)860{861uint procType, i;862struct tgsi_parse_context parse;863unsigned current_depth = 0;864865memset(info, 0, sizeof(*info));866for (i = 0; i < TGSI_FILE_COUNT; i++)867info->file_max[i] = -1;868for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)869info->const_file_max[i] = -1;870for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)871info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;872873/**874** Setup to begin parsing input shader875**/876if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {877debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");878return;879}880procType = parse.FullHeader.Processor.Processor;881assert(procType == PIPE_SHADER_FRAGMENT ||882procType == PIPE_SHADER_VERTEX ||883procType == PIPE_SHADER_GEOMETRY ||884procType == PIPE_SHADER_TESS_CTRL ||885procType == PIPE_SHADER_TESS_EVAL ||886procType == PIPE_SHADER_COMPUTE);887info->processor = procType;888info->num_tokens = tgsi_num_tokens(parse.Tokens);889890if (procType == PIPE_SHADER_GEOMETRY)891info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;892893/**894** Loop over incoming program tokens/instructions895*/896while (!tgsi_parse_end_of_tokens(&parse)) {897tgsi_parse_token( &parse );898899switch( parse.FullToken.Token.Type ) {900case TGSI_TOKEN_TYPE_INSTRUCTION:901scan_instruction(info, &parse.FullToken.FullInstruction,902¤t_depth);903break;904case TGSI_TOKEN_TYPE_DECLARATION:905scan_declaration(info, &parse.FullToken.FullDeclaration);906break;907case TGSI_TOKEN_TYPE_IMMEDIATE:908scan_immediate(info);909break;910case TGSI_TOKEN_TYPE_PROPERTY:911scan_property(info, &parse.FullToken.FullProperty);912break;913default:914assert(!"Unexpected TGSI token type");915}916}917918info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||919info->opcode_count[TGSI_OPCODE_KILL]);920921/* The dimensions of the IN decleration in geometry shader have922* to be deduced from the type of the input primitive.923*/924if (procType == PIPE_SHADER_GEOMETRY) {925unsigned input_primitive =926info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];927int num_verts = u_vertices_per_prim(input_primitive);928int j;929info->file_count[TGSI_FILE_INPUT] = num_verts;930info->file_max[TGSI_FILE_INPUT] =931MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);932for (j = 0; j < num_verts; ++j) {933info->file_mask[TGSI_FILE_INPUT] |= (1 << j);934}935}936937tgsi_parse_free(&parse);938}939940/**941* Collect information about the arrays of a given register file.942*943* @param tokens TGSI shader944* @param file the register file to scan through945* @param max_array_id number of entries in @p arrays; should be equal to the946* highest array id, i.e. tgsi_shader_info::array_max[file].947* @param arrays info for array of each ID will be written to arrays[ID - 1].948*/949void950tgsi_scan_arrays(const struct tgsi_token *tokens,951unsigned file,952unsigned max_array_id,953struct tgsi_array_info *arrays)954{955struct tgsi_parse_context parse;956957if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {958debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");959return;960}961962memset(arrays, 0, sizeof(arrays[0]) * max_array_id);963964while (!tgsi_parse_end_of_tokens(&parse)) {965struct tgsi_full_instruction *inst;966967tgsi_parse_token(&parse);968969if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {970struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;971972if (decl->Declaration.Array && decl->Declaration.File == file &&973decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {974struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];975assert(!array->declared);976array->declared = true;977array->range = decl->Range;978}979}980981if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)982continue;983984inst = &parse.FullToken.FullInstruction;985for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {986const struct tgsi_full_dst_register *dst = &inst->Dst[i];987if (dst->Register.File != file)988continue;989990if (dst->Register.Indirect) {991if (dst->Indirect.ArrayID > 0 &&992dst->Indirect.ArrayID <= max_array_id) {993arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;994} else {995/* Indirect writes without an ArrayID can write anywhere. */996for (unsigned j = 0; j < max_array_id; ++j)997arrays[j].writemask |= dst->Register.WriteMask;998}999} else {1000/* Check whether the write falls into any of the arrays anyway. */1001for (unsigned j = 0; j < max_array_id; ++j) {1002struct tgsi_array_info *array = &arrays[j];1003if (array->declared &&1004dst->Register.Index >= array->range.First &&1005dst->Register.Index <= array->range.Last)1006array->writemask |= dst->Register.WriteMask;1007}1008}1009}1010}10111012tgsi_parse_free(&parse);10131014return;1015}10161017static void1018check_no_subroutines(const struct tgsi_full_instruction *inst)1019{1020switch (inst->Instruction.Opcode) {1021case TGSI_OPCODE_BGNSUB:1022case TGSI_OPCODE_ENDSUB:1023case TGSI_OPCODE_CAL:1024unreachable("subroutines unhandled");1025}1026}10271028static unsigned1029get_inst_tessfactor_writemask(const struct tgsi_shader_info *info,1030const struct tgsi_full_instruction *inst)1031{1032unsigned writemask = 0;10331034for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {1035const struct tgsi_full_dst_register *dst = &inst->Dst[i];10361037if (dst->Register.File == TGSI_FILE_OUTPUT &&1038!dst->Register.Indirect) {1039unsigned name = info->output_semantic_name[dst->Register.Index];10401041if (name == TGSI_SEMANTIC_TESSINNER)1042writemask |= dst->Register.WriteMask;1043else if (name == TGSI_SEMANTIC_TESSOUTER)1044writemask |= dst->Register.WriteMask << 4;1045}1046}1047return writemask;1048}10491050static unsigned1051get_block_tessfactor_writemask(const struct tgsi_shader_info *info,1052struct tgsi_parse_context *parse,1053unsigned end_opcode)1054{1055struct tgsi_full_instruction *inst;1056unsigned writemask = 0;10571058tgsi_parse_token(parse);1059assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);1060inst = &parse->FullToken.FullInstruction;1061check_no_subroutines(inst);10621063while (inst->Instruction.Opcode != end_opcode) {10641065/* Recursively process nested blocks. */1066switch (inst->Instruction.Opcode) {1067case TGSI_OPCODE_IF:1068case TGSI_OPCODE_UIF:1069writemask |=1070get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF);1071break;10721073case TGSI_OPCODE_BGNLOOP:1074writemask |=1075get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);1076break;10771078case TGSI_OPCODE_BARRIER:1079unreachable("nested BARRIER is illegal");1080break;10811082default:1083writemask |= get_inst_tessfactor_writemask(info, inst);1084}10851086tgsi_parse_token(parse);1087assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);1088inst = &parse->FullToken.FullInstruction;1089check_no_subroutines(inst);1090}10911092return writemask;1093}10941095static void1096get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info,1097struct tgsi_parse_context *parse,1098unsigned *upper_block_tf_writemask,1099unsigned *cond_block_tf_writemask)1100{1101struct tgsi_full_instruction *inst;1102unsigned then_tessfactor_writemask = 0;1103unsigned else_tessfactor_writemask = 0;1104unsigned writemask;1105bool is_then = true;11061107tgsi_parse_token(parse);1108assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);1109inst = &parse->FullToken.FullInstruction;1110check_no_subroutines(inst);11111112while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF) {11131114switch (inst->Instruction.Opcode) {1115case TGSI_OPCODE_ELSE:1116is_then = false;1117break;11181119/* Recursively process nested blocks. */1120case TGSI_OPCODE_IF:1121case TGSI_OPCODE_UIF:1122get_if_block_tessfactor_writemask(info, parse,1123is_then ? &then_tessfactor_writemask :1124&else_tessfactor_writemask,1125cond_block_tf_writemask);1126break;11271128case TGSI_OPCODE_BGNLOOP:1129*cond_block_tf_writemask |=1130get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);1131break;11321133case TGSI_OPCODE_BARRIER:1134unreachable("nested BARRIER is illegal");1135break;1136default:1137/* Process an instruction in the current block. */1138writemask = get_inst_tessfactor_writemask(info, inst);11391140if (writemask) {1141if (is_then)1142then_tessfactor_writemask |= writemask;1143else1144else_tessfactor_writemask |= writemask;1145}1146}11471148tgsi_parse_token(parse);1149assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);1150inst = &parse->FullToken.FullInstruction;1151check_no_subroutines(inst);1152}11531154if (then_tessfactor_writemask || else_tessfactor_writemask) {1155/* If both statements write the same tess factor channels,1156* we can say that the upper block writes them too. */1157*upper_block_tf_writemask |= then_tessfactor_writemask &1158else_tessfactor_writemask;1159*cond_block_tf_writemask |= then_tessfactor_writemask |1160else_tessfactor_writemask;1161}1162}11631164void1165tgsi_scan_tess_ctrl(const struct tgsi_token *tokens,1166const struct tgsi_shader_info *info,1167struct tgsi_tessctrl_info *out)1168{1169memset(out, 0, sizeof(*out));11701171if (info->processor != PIPE_SHADER_TESS_CTRL)1172return;11731174struct tgsi_parse_context parse;1175if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {1176debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");1177return;1178}11791180/* The pass works as follows:1181* If all codepaths write tess factors, we can say that all invocations1182* define tess factors.1183*1184* Each tess factor channel is tracked separately.1185*/1186unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */1187unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */11881189/* Initial value = true. Here the pass will accumulate results from multiple1190* segments surrounded by barriers. If tess factors aren't written at all,1191* it's a shader bug and we don't care if this will be true.1192*/1193out->tessfactors_are_def_in_all_invocs = true;11941195while (!tgsi_parse_end_of_tokens(&parse)) {1196tgsi_parse_token(&parse);11971198if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)1199continue;12001201struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction;1202check_no_subroutines(inst);12031204/* Process nested blocks. */1205switch (inst->Instruction.Opcode) {1206case TGSI_OPCODE_IF:1207case TGSI_OPCODE_UIF:1208get_if_block_tessfactor_writemask(info, &parse,1209&main_block_tf_writemask,1210&cond_block_tf_writemask);1211continue;12121213case TGSI_OPCODE_BGNLOOP:1214cond_block_tf_writemask |=1215get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDLOOP);1216continue;12171218case TGSI_OPCODE_BARRIER:1219/* The following case must be prevented:1220* gl_TessLevelInner = ...;1221* barrier();1222* if (gl_InvocationID == 1)1223* gl_TessLevelInner = ...;1224*1225* If you consider disjoint code segments separated by barriers, each1226* such segment that writes tess factor channels should write the same1227* channels in all codepaths within that segment.1228*/1229if (main_block_tf_writemask || cond_block_tf_writemask) {1230/* Accumulate the result: */1231out->tessfactors_are_def_in_all_invocs &=1232!(cond_block_tf_writemask & ~main_block_tf_writemask);12331234/* Analyze the next code segment from scratch. */1235main_block_tf_writemask = 0;1236cond_block_tf_writemask = 0;1237}1238continue;1239}12401241main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst);1242}12431244/* Accumulate the result for the last code segment separated by a barrier. */1245if (main_block_tf_writemask || cond_block_tf_writemask) {1246out->tessfactors_are_def_in_all_invocs &=1247!(cond_block_tf_writemask & ~main_block_tf_writemask);1248}12491250tgsi_parse_free(&parse);1251}125212531254