/** Return number of src args for given instruction */ GLuint brw_wm_nr_args( GLuint opcode ) { switch (opcode) { case WM_FRONTFACING: case WM_PIXELXY: return 0; case WM_CINTERP: case WM_WPOSXY: case WM_DELTAXY: return 1; case WM_LINTERP: case WM_PIXELW: return 2; case WM_FB_WRITE: case WM_PINTERP: return 3; case TGSI_OPCODE_TEX: case TGSI_OPCODE_TXP: case TGSI_OPCODE_TXB: case TGSI_OPCODE_TXD: /* sampler arg is held as a field in the instruction, not in an * actual register: */ return tgsi_get_opcode_info(opcode)->num_src - 1; default: assert(opcode < MAX_OPCODE); return tgsi_get_opcode_info(opcode)->num_src; } }
static void print_opcode( unsigned opcode ) { switch (opcode) { case WM_PIXELXY: debug_printf("PIXELXY"); break; case WM_DELTAXY: debug_printf("DELTAXY"); break; case WM_PIXELW: debug_printf("PIXELW"); break; case WM_WPOSXY: debug_printf("WPOSXY"); break; case WM_PINTERP: debug_printf("PINTERP"); break; case WM_LINTERP: debug_printf("LINTERP"); break; case WM_CINTERP: debug_printf("CINTERP"); break; case WM_FB_WRITE: debug_printf("FB_WRITE"); break; case WM_FRONTFACING: debug_printf("FRONTFACING"); break; default: debug_printf("%s", tgsi_get_opcode_info(opcode)->mnemonic); break; } }
/** * Is the opcode a "true" texture instruction which samples from a * texture map? */ static bool is_texture_inst(unsigned opcode) { return (opcode != TGSI_OPCODE_TXQ && opcode != TGSI_OPCODE_TXQS && opcode != TGSI_OPCODE_TXQ_LZ && opcode != TGSI_OPCODE_LODQ && tgsi_get_opcode_info(opcode)->is_tex); }
static void validate( unsigned opcode, unsigned nr_dst, unsigned nr_src ) { #ifdef DEBUG const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); assert(info); if(info) { assert(nr_dst == info->num_dst); assert(nr_src == info->num_src); } #endif }
static boolean iter_instruction( struct tgsi_iterate_context *iter, struct tgsi_full_instruction *inst ) { struct dump_ctx *ctx = (struct dump_ctx *) iter; uint instno = ctx->instno++; const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); uint i; boolean first_reg = TRUE; INSTID( instno ); TXT( ": " ); ctx->indent -= info->pre_dedent; for(i = 0; (int)i < ctx->indent; ++i) TXT( " " ); ctx->indent += info->post_indent; if (inst->Instruction.Predicate) { CHR( '(' ); if (inst->Predicate.Negate) CHR( '!' ); TXT( "PRED[" ); SID( inst->Predicate.Index ); CHR( ']' ); if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X || inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y || inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z || inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) { CHR( '.' ); ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names ); ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names ); ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names ); ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names ); } TXT( ") " ); } TXT( info->mnemonic ); switch (inst->Instruction.Saturate) { case TGSI_SAT_NONE: break; case TGSI_SAT_ZERO_ONE: TXT( "_SAT" ); break; case TGSI_SAT_MINUS_PLUS_ONE: TXT( "_SATNV" ); break; default: assert( 0 ); } for (i = 0; i < inst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &inst->Dst[i]; if (!first_reg) CHR( ',' ); CHR( ' ' ); _dump_register_dst( ctx, dst ); _dump_writemask( ctx, dst->Register.WriteMask ); first_reg = FALSE; } for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { const struct tgsi_full_src_register *src = &inst->Src[i]; if (!first_reg) CHR( ',' ); CHR( ' ' ); if (src->Register.Negate) CHR( '-' ); if (src->Register.Absolute) CHR( '|' ); _dump_register_src(ctx, src); if (src->Register.SwizzleX != TGSI_SWIZZLE_X || src->Register.SwizzleY != TGSI_SWIZZLE_Y || src->Register.SwizzleZ != TGSI_SWIZZLE_Z || src->Register.SwizzleW != TGSI_SWIZZLE_W) { CHR( '.' ); ENM( src->Register.SwizzleX, tgsi_swizzle_names ); ENM( src->Register.SwizzleY, tgsi_swizzle_names ); ENM( src->Register.SwizzleZ, tgsi_swizzle_names ); ENM( src->Register.SwizzleW, tgsi_swizzle_names ); } if (src->Register.Absolute) CHR( '|' ); first_reg = FALSE; } if (inst->Instruction.Texture) { TXT( ", " ); ENM( inst->Texture.Texture, tgsi_texture_names ); for (i = 0; i < inst->Texture.NumOffsets; i++) { TXT( ", " ); ENM( inst->TexOffsets[i].File, tgsi_file_names); CHR( '[' ); SID( inst->TexOffsets[i].Index ); CHR( ']' ); CHR( '.' ); ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names); ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names); ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names); } } switch (inst->Instruction.Opcode) { case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: case TGSI_OPCODE_ELSE: case TGSI_OPCODE_BGNLOOP: case TGSI_OPCODE_ENDLOOP: case TGSI_OPCODE_CAL: TXT( " :" ); UID( inst->Label.Label ); break; } /* update indentation */ if (inst->Instruction.Opcode == TGSI_OPCODE_IF || inst->Instruction.Opcode == TGSI_OPCODE_UIF || inst->Instruction.Opcode == TGSI_OPCODE_ELSE || inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { ctx->indentation += indent_spaces; } EOL(); return TRUE; }
static boolean parse_instruction( struct translate_ctx *ctx, boolean has_label ) { uint i; uint saturate = 0; const struct tgsi_opcode_info *info; struct tgsi_full_instruction inst; const char *cur; uint advance; inst = tgsi_default_full_instruction(); /* Parse predicate. */ eat_opt_white( &ctx->cur ); if (*ctx->cur == '(') { uint file; int index; uint swizzle[4]; boolean parsed_swizzle; inst.Instruction.Predicate = 1; ctx->cur++; if (*ctx->cur == '!') { ctx->cur++; inst.Predicate.Negate = 1; } if (!parse_register_1d( ctx, &file, &index )) return FALSE; if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) { if (parsed_swizzle) { inst.Predicate.SwizzleX = swizzle[0]; inst.Predicate.SwizzleY = swizzle[1]; inst.Predicate.SwizzleZ = swizzle[2]; inst.Predicate.SwizzleW = swizzle[3]; } } if (*ctx->cur != ')') { report_error( ctx, "Expected `)'" ); return FALSE; } ctx->cur++; } /* Parse instruction name. */ eat_opt_white( &ctx->cur ); for (i = 0; i < TGSI_OPCODE_LAST; i++) { cur = ctx->cur; info = tgsi_get_opcode_info( i ); if (match_inst(&cur, &saturate, info)) { if (info->num_dst + info->num_src + info->is_tex == 0) { ctx->cur = cur; break; } else if (*cur == '\0' || eat_white( &cur )) { ctx->cur = cur; break; } } } if (i == TGSI_OPCODE_LAST) { if (has_label) report_error( ctx, "Unknown opcode" ); else report_error( ctx, "Expected `DCL', `IMM' or a label" ); return FALSE; } inst.Instruction.Opcode = i; inst.Instruction.Saturate = saturate; inst.Instruction.NumDstRegs = info->num_dst; inst.Instruction.NumSrcRegs = info->num_src; if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) { /* * These are not considered tex opcodes here (no additional * target argument) however we're required to set the Texture * bit so we can set the number of tex offsets. */ inst.Instruction.Texture = 1; inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN; } if ((i >= TGSI_OPCODE_LOAD && i <= TGSI_OPCODE_ATOMIMAX) || i == TGSI_OPCODE_RESQ) { inst.Instruction.Memory = 1; inst.Memory.Qualifier = 0; } /* Parse instruction operands. */ for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { if (i > 0) { eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); } if (i < info->num_dst) { if (!parse_dst_operand( ctx, &inst.Dst[i] )) return FALSE; } else if (i < info->num_dst + info->num_src) { if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) return FALSE; } else { uint j; for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) { inst.Instruction.Texture = 1; inst.Texture.Texture = j; break; } } if (j == TGSI_TEXTURE_COUNT) { report_error( ctx, "Expected texture target" ); return FALSE; } } } cur = ctx->cur; eat_opt_white( &cur ); for (i = 0; inst.Instruction.Texture && *cur == ','; i++) { cur++; eat_opt_white( &cur ); ctx->cur = cur; if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] )) return FALSE; cur = ctx->cur; eat_opt_white( &cur ); } inst.Texture.NumOffsets = i; cur = ctx->cur; eat_opt_white(&cur); for (i = 0; inst.Instruction.Memory && *cur == ','; i++) { uint j; cur++; eat_opt_white(&cur); ctx->cur = cur; for (j = 0; j < 3; j++) { if (str_match_nocase_whole(&ctx->cur, tgsi_memory_names[j])) { inst.Memory.Qualifier |= 1U << j; break; } } if (j == 3) { report_error(ctx, "Expected memory qualifier"); return FALSE; } cur = ctx->cur; eat_opt_white(&cur); } cur = ctx->cur; eat_opt_white( &cur ); if (info->is_branch && *cur == ':') { uint target; cur++; eat_opt_white( &cur ); if (!parse_uint( &cur, &target )) { report_error( ctx, "Expected a label" ); return FALSE; } inst.Instruction.Label = 1; inst.Label.Label = target; ctx->cur = cur; } advance = tgsi_build_full_instruction( &inst, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }
void lp_build_tgsi_aos(struct gallivm_state *gallivm, const struct tgsi_token *tokens, struct lp_type type, const unsigned char swizzles[4], LLVMValueRef consts_ptr, const LLVMValueRef *inputs, LLVMValueRef *outputs, struct lp_build_sampler_aos *sampler, const struct tgsi_shader_info *info) { struct lp_build_tgsi_aos_context bld; struct tgsi_parse_context parse; uint num_immediates = 0; unsigned chan; int pc = 0; /* Setup build context */ memset(&bld, 0, sizeof bld); lp_build_context_init(&bld.bld_base.base, gallivm, type); lp_build_context_init(&bld.bld_base.uint_bld, gallivm, lp_uint_type(type)); lp_build_context_init(&bld.bld_base.int_bld, gallivm, lp_int_type(type)); lp_build_context_init(&bld.int_bld, gallivm, lp_int_type(type)); for (chan = 0; chan < 4; ++chan) { bld.swizzles[chan] = swizzles[chan]; bld.inv_swizzles[swizzles[chan]] = chan; } bld.inputs = inputs; bld.outputs = outputs; bld.consts_ptr = consts_ptr; bld.sampler = sampler; bld.indirect_files = info->indirect_files; bld.bld_base.emit_swizzle = swizzle_aos; bld.bld_base.info = info; bld.bld_base.emit_fetch_funcs[TGSI_FILE_CONSTANT] = emit_fetch_constant; bld.bld_base.emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch_immediate; bld.bld_base.emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_input; bld.bld_base.emit_fetch_funcs[TGSI_FILE_TEMPORARY] = emit_fetch_temporary; /* Set opcode actions */ lp_set_default_actions_cpu(&bld.bld_base); if (!lp_bld_tgsi_list_init(&bld.bld_base)) { return; } tgsi_parse_init(&parse, tokens); while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); switch(parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: /* Inputs already interpolated */ lp_emit_declaration_aos(&bld, &parse.FullToken.FullDeclaration); break; case TGSI_TOKEN_TYPE_INSTRUCTION: /* save expanded instruction */ lp_bld_tgsi_add_instruction(&bld.bld_base, &parse.FullToken.FullInstruction); break; case TGSI_TOKEN_TYPE_IMMEDIATE: /* simply copy the immediate values into the next immediates[] slot */ { const uint size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1; float imm[4]; assert(size <= 4); assert(num_immediates < LP_MAX_TGSI_IMMEDIATES); for (chan = 0; chan < 4; ++chan) { imm[chan] = 0.0f; } for (chan = 0; chan < size; ++chan) { unsigned swizzle = bld.swizzles[chan]; imm[swizzle] = parse.FullToken.FullImmediate.u[chan].Float; } bld.immediates[num_immediates] = lp_build_const_aos(gallivm, type, imm[0], imm[1], imm[2], imm[3], NULL); num_immediates++; } break; case TGSI_TOKEN_TYPE_PROPERTY: break; default: assert(0); } } while (pc != -1) { struct tgsi_full_instruction *instr = bld.bld_base.instructions + pc; const struct tgsi_opcode_info *opcode_info = tgsi_get_opcode_info(instr->Instruction.Opcode); if (!lp_emit_instruction_aos(&bld, instr, opcode_info, &pc)) _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n", opcode_info->mnemonic); } if (0) { LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder); LLVMValueRef function = LLVMGetBasicBlockParent(block); debug_printf("11111111111111111111111111111 \n"); tgsi_dump(tokens, 0); lp_debug_dump_value(function); debug_printf("2222222222222222222222222222 \n"); } tgsi_parse_free(&parse); FREE(bld.bld_base.instructions); if (0) { LLVMModuleRef module = LLVMGetGlobalParent( LLVMGetBasicBlockParent(LLVMGetInsertBlock(gallivm->builder))); LLVMDumpModule(module); } }
const char * tgsi_get_opcode_name( uint opcode ) { const struct tgsi_opcode_info *info = tgsi_get_opcode_info(opcode); return info->mnemonic; }
static void dump_instruction_verbose( struct tgsi_full_instruction *inst, unsigned ignored, unsigned deflt, struct tgsi_full_instruction *fi ) { unsigned i; TXT( "\nOpcode : OPCODE_" ); TXT( tgsi_get_opcode_info( inst->Instruction.Opcode )->mnemonic ); if( deflt || fi->Instruction.Saturate != inst->Instruction.Saturate ) { TXT( "\nSaturate : " ); ENM( inst->Instruction.Saturate, TGSI_SATS ); } if( deflt || fi->Instruction.NumDstRegs != inst->Instruction.NumDstRegs ) { TXT( "\nNumDstRegs : " ); UID( inst->Instruction.NumDstRegs ); } if( deflt || fi->Instruction.NumSrcRegs != inst->Instruction.NumSrcRegs ) { TXT( "\nNumSrcRegs : " ); UID( inst->Instruction.NumSrcRegs ); } if( ignored ) { TXT( "\nPadding : " ); UIX( inst->Instruction.Padding ); } if( deflt || tgsi_compare_instruction_ext_nv( inst->InstructionExtNv, fi->InstructionExtNv ) ) { EOL(); TXT( "\nType : " ); ENM( inst->InstructionExtNv.Type, TGSI_INSTRUCTION_EXTS ); if( deflt || fi->InstructionExtNv.Precision != inst->InstructionExtNv.Precision ) { TXT( "\nPrecision : " ); ENM( inst->InstructionExtNv.Precision, TGSI_PRECISIONS ); } if( deflt || fi->InstructionExtNv.CondDstIndex != inst->InstructionExtNv.CondDstIndex ) { TXT( "\nCondDstIndex : " ); UID( inst->InstructionExtNv.CondDstIndex ); } if( deflt || fi->InstructionExtNv.CondFlowIndex != inst->InstructionExtNv.CondFlowIndex ) { TXT( "\nCondFlowIndex : " ); UID( inst->InstructionExtNv.CondFlowIndex ); } if( deflt || fi->InstructionExtNv.CondMask != inst->InstructionExtNv.CondMask ) { TXT( "\nCondMask : " ); ENM( inst->InstructionExtNv.CondMask, TGSI_CCS ); } if( deflt || fi->InstructionExtNv.CondSwizzleX != inst->InstructionExtNv.CondSwizzleX ) { TXT( "\nCondSwizzleX : " ); ENM( inst->InstructionExtNv.CondSwizzleX, TGSI_SWIZZLES ); } if( deflt || fi->InstructionExtNv.CondSwizzleY != inst->InstructionExtNv.CondSwizzleY ) { TXT( "\nCondSwizzleY : " ); ENM( inst->InstructionExtNv.CondSwizzleY, TGSI_SWIZZLES ); } if( deflt || fi->InstructionExtNv.CondSwizzleZ != inst->InstructionExtNv.CondSwizzleZ ) { TXT( "\nCondSwizzleZ : " ); ENM( inst->InstructionExtNv.CondSwizzleZ, TGSI_SWIZZLES ); } if( deflt || fi->InstructionExtNv.CondSwizzleW != inst->InstructionExtNv.CondSwizzleW ) { TXT( "\nCondSwizzleW : " ); ENM( inst->InstructionExtNv.CondSwizzleW, TGSI_SWIZZLES ); } if( deflt || fi->InstructionExtNv.CondDstUpdate != inst->InstructionExtNv.CondDstUpdate ) { TXT( "\nCondDstUpdate : " ); UID( inst->InstructionExtNv.CondDstUpdate ); } if( deflt || fi->InstructionExtNv.CondFlowEnable != inst->InstructionExtNv.CondFlowEnable ) { TXT( "\nCondFlowEnable: " ); UID( inst->InstructionExtNv.CondFlowEnable ); } if( ignored ) { TXT( "\nPadding : " ); UIX( inst->InstructionExtNv.Padding ); if( deflt || fi->InstructionExtNv.Extended != inst->InstructionExtNv.Extended ) { TXT( "\nExtended : " ); UID( inst->InstructionExtNv.Extended ); } } } if( deflt || tgsi_compare_instruction_ext_label( inst->InstructionExtLabel, fi->InstructionExtLabel ) ) { EOL(); TXT( "\nType : " ); ENM( inst->InstructionExtLabel.Type, TGSI_INSTRUCTION_EXTS ); if( deflt || fi->InstructionExtLabel.Label != inst->InstructionExtLabel.Label ) { TXT( "\nLabel : " ); UID( inst->InstructionExtLabel.Label ); } if( ignored ) { TXT( "\nPadding : " ); UIX( inst->InstructionExtLabel.Padding ); if( deflt || fi->InstructionExtLabel.Extended != inst->InstructionExtLabel.Extended ) { TXT( "\nExtended: " ); UID( inst->InstructionExtLabel.Extended ); } } } if( deflt || tgsi_compare_instruction_ext_texture( inst->InstructionExtTexture, fi->InstructionExtTexture ) ) { EOL(); TXT( "\nType : " ); ENM( inst->InstructionExtTexture.Type, TGSI_INSTRUCTION_EXTS ); if( deflt || fi->InstructionExtTexture.Texture != inst->InstructionExtTexture.Texture ) { TXT( "\nTexture : " ); ENM( inst->InstructionExtTexture.Texture, TGSI_TEXTURES ); } if( ignored ) { TXT( "\nPadding : " ); UIX( inst->InstructionExtTexture.Padding ); if( deflt || fi->InstructionExtTexture.Extended != inst->InstructionExtTexture.Extended ) { TXT( "\nExtended: " ); UID( inst->InstructionExtTexture.Extended ); } } } for( i = 0; i < inst->Instruction.NumDstRegs; i++ ) { struct tgsi_full_dst_register *dst = &inst->FullDstRegisters[i]; struct tgsi_full_dst_register *fd = &fi->FullDstRegisters[i]; EOL(); TXT( "\nFile : " ); ENM( dst->DstRegister.File, TGSI_FILES ); if( deflt || fd->DstRegister.WriteMask != dst->DstRegister.WriteMask ) { TXT( "\nWriteMask: " ); ENM( dst->DstRegister.WriteMask, TGSI_WRITEMASKS ); } if( ignored ) { if( deflt || fd->DstRegister.Indirect != dst->DstRegister.Indirect ) { TXT( "\nIndirect : " ); UID( dst->DstRegister.Indirect ); } if( deflt || fd->DstRegister.Dimension != dst->DstRegister.Dimension ) { TXT( "\nDimension: " ); UID( dst->DstRegister.Dimension ); } } if( deflt || fd->DstRegister.Index != dst->DstRegister.Index ) { TXT( "\nIndex : " ); SID( dst->DstRegister.Index ); } if( ignored ) { TXT( "\nPadding : " ); UIX( dst->DstRegister.Padding ); if( deflt || fd->DstRegister.Extended != dst->DstRegister.Extended ) { TXT( "\nExtended : " ); UID( dst->DstRegister.Extended ); } } if( deflt || tgsi_compare_dst_register_ext_concode( dst->DstRegisterExtConcode, fd->DstRegisterExtConcode ) ) { EOL(); TXT( "\nType : " ); ENM( dst->DstRegisterExtConcode.Type, TGSI_DST_REGISTER_EXTS ); if( deflt || fd->DstRegisterExtConcode.CondMask != dst->DstRegisterExtConcode.CondMask ) { TXT( "\nCondMask : " ); ENM( dst->DstRegisterExtConcode.CondMask, TGSI_CCS ); } if( deflt || fd->DstRegisterExtConcode.CondSwizzleX != dst->DstRegisterExtConcode.CondSwizzleX ) { TXT( "\nCondSwizzleX: " ); ENM( dst->DstRegisterExtConcode.CondSwizzleX, TGSI_SWIZZLES ); } if( deflt || fd->DstRegisterExtConcode.CondSwizzleY != dst->DstRegisterExtConcode.CondSwizzleY ) { TXT( "\nCondSwizzleY: " ); ENM( dst->DstRegisterExtConcode.CondSwizzleY, TGSI_SWIZZLES ); } if( deflt || fd->DstRegisterExtConcode.CondSwizzleZ != dst->DstRegisterExtConcode.CondSwizzleZ ) { TXT( "\nCondSwizzleZ: " ); ENM( dst->DstRegisterExtConcode.CondSwizzleZ, TGSI_SWIZZLES ); } if( deflt || fd->DstRegisterExtConcode.CondSwizzleW != dst->DstRegisterExtConcode.CondSwizzleW ) { TXT( "\nCondSwizzleW: " ); ENM( dst->DstRegisterExtConcode.CondSwizzleW, TGSI_SWIZZLES ); } if( deflt || fd->DstRegisterExtConcode.CondSrcIndex != dst->DstRegisterExtConcode.CondSrcIndex ) { TXT( "\nCondSrcIndex: " ); UID( dst->DstRegisterExtConcode.CondSrcIndex ); } if( ignored ) { TXT( "\nPadding : " ); UIX( dst->DstRegisterExtConcode.Padding ); if( deflt || fd->DstRegisterExtConcode.Extended != dst->DstRegisterExtConcode.Extended ) { TXT( "\nExtended : " ); UID( dst->DstRegisterExtConcode.Extended ); } } } if( deflt || tgsi_compare_dst_register_ext_modulate( dst->DstRegisterExtModulate, fd->DstRegisterExtModulate ) ) { EOL(); TXT( "\nType : " ); ENM( dst->DstRegisterExtModulate.Type, TGSI_DST_REGISTER_EXTS ); if( deflt || fd->DstRegisterExtModulate.Modulate != dst->DstRegisterExtModulate.Modulate ) { TXT( "\nModulate: " ); ENM( dst->DstRegisterExtModulate.Modulate, TGSI_MODULATES ); } if( ignored ) { TXT( "\nPadding : " ); UIX( dst->DstRegisterExtModulate.Padding ); if( deflt || fd->DstRegisterExtModulate.Extended != dst->DstRegisterExtModulate.Extended ) { TXT( "\nExtended: " ); UID( dst->DstRegisterExtModulate.Extended ); } } } } for( i = 0; i < inst->Instruction.NumSrcRegs; i++ ) { struct tgsi_full_src_register *src = &inst->FullSrcRegisters[i]; struct tgsi_full_src_register *fs = &fi->FullSrcRegisters[i]; EOL(); TXT( "\nFile : "); ENM( src->SrcRegister.File, TGSI_FILES ); if( deflt || fs->SrcRegister.SwizzleX != src->SrcRegister.SwizzleX ) { TXT( "\nSwizzleX : " ); ENM( src->SrcRegister.SwizzleX, TGSI_SWIZZLES ); } if( deflt || fs->SrcRegister.SwizzleY != src->SrcRegister.SwizzleY ) { TXT( "\nSwizzleY : " ); ENM( src->SrcRegister.SwizzleY, TGSI_SWIZZLES ); } if( deflt || fs->SrcRegister.SwizzleZ != src->SrcRegister.SwizzleZ ) { TXT( "\nSwizzleZ : " ); ENM( src->SrcRegister.SwizzleZ, TGSI_SWIZZLES ); } if( deflt || fs->SrcRegister.SwizzleW != src->SrcRegister.SwizzleW ) { TXT( "\nSwizzleW : " ); ENM( src->SrcRegister.SwizzleW, TGSI_SWIZZLES ); } if( deflt || fs->SrcRegister.Negate != src->SrcRegister.Negate ) { TXT( "\nNegate : " ); UID( src->SrcRegister.Negate ); } if( ignored ) { if( deflt || fs->SrcRegister.Indirect != src->SrcRegister.Indirect ) { TXT( "\nIndirect : " ); UID( src->SrcRegister.Indirect ); } if( deflt || fs->SrcRegister.Dimension != src->SrcRegister.Dimension ) { TXT( "\nDimension: " ); UID( src->SrcRegister.Dimension ); } } if( deflt || fs->SrcRegister.Index != src->SrcRegister.Index ) { TXT( "\nIndex : " ); SID( src->SrcRegister.Index ); } if( ignored ) { if( deflt || fs->SrcRegister.Extended != src->SrcRegister.Extended ) { TXT( "\nExtended : " ); UID( src->SrcRegister.Extended ); } } if( deflt || tgsi_compare_src_register_ext_swz( src->SrcRegisterExtSwz, fs->SrcRegisterExtSwz ) ) { EOL(); TXT( "\nType : " ); ENM( src->SrcRegisterExtSwz.Type, TGSI_SRC_REGISTER_EXTS ); if( deflt || fs->SrcRegisterExtSwz.ExtSwizzleX != src->SrcRegisterExtSwz.ExtSwizzleX ) { TXT( "\nExtSwizzleX: " ); ENM( src->SrcRegisterExtSwz.ExtSwizzleX, TGSI_EXTSWIZZLES ); } if( deflt || fs->SrcRegisterExtSwz.ExtSwizzleY != src->SrcRegisterExtSwz.ExtSwizzleY ) { TXT( "\nExtSwizzleY: " ); ENM( src->SrcRegisterExtSwz.ExtSwizzleY, TGSI_EXTSWIZZLES ); } if( deflt || fs->SrcRegisterExtSwz.ExtSwizzleZ != src->SrcRegisterExtSwz.ExtSwizzleZ ) { TXT( "\nExtSwizzleZ: " ); ENM( src->SrcRegisterExtSwz.ExtSwizzleZ, TGSI_EXTSWIZZLES ); } if( deflt || fs->SrcRegisterExtSwz.ExtSwizzleW != src->SrcRegisterExtSwz.ExtSwizzleW ) { TXT( "\nExtSwizzleW: " ); ENM( src->SrcRegisterExtSwz.ExtSwizzleW, TGSI_EXTSWIZZLES ); } if( deflt || fs->SrcRegisterExtSwz.NegateX != src->SrcRegisterExtSwz.NegateX ) { TXT( "\nNegateX : " ); UID( src->SrcRegisterExtSwz.NegateX ); } if( deflt || fs->SrcRegisterExtSwz.NegateY != src->SrcRegisterExtSwz.NegateY ) { TXT( "\nNegateY : " ); UID( src->SrcRegisterExtSwz.NegateY ); } if( deflt || fs->SrcRegisterExtSwz.NegateZ != src->SrcRegisterExtSwz.NegateZ ) { TXT( "\nNegateZ : " ); UID( src->SrcRegisterExtSwz.NegateZ ); } if( deflt || fs->SrcRegisterExtSwz.NegateW != src->SrcRegisterExtSwz.NegateW ) { TXT( "\nNegateW : " ); UID( src->SrcRegisterExtSwz.NegateW ); } if( ignored ) { TXT( "\nPadding : " ); UIX( src->SrcRegisterExtSwz.Padding ); if( deflt || fs->SrcRegisterExtSwz.Extended != src->SrcRegisterExtSwz.Extended ) { TXT( "\nExtended : " ); UID( src->SrcRegisterExtSwz.Extended ); } } } if( deflt || tgsi_compare_src_register_ext_mod( src->SrcRegisterExtMod, fs->SrcRegisterExtMod ) ) { EOL(); TXT( "\nType : " ); ENM( src->SrcRegisterExtMod.Type, TGSI_SRC_REGISTER_EXTS ); if( deflt || fs->SrcRegisterExtMod.Complement != src->SrcRegisterExtMod.Complement ) { TXT( "\nComplement: " ); UID( src->SrcRegisterExtMod.Complement ); } if( deflt || fs->SrcRegisterExtMod.Bias != src->SrcRegisterExtMod.Bias ) { TXT( "\nBias : " ); UID( src->SrcRegisterExtMod.Bias ); } if( deflt || fs->SrcRegisterExtMod.Scale2X != src->SrcRegisterExtMod.Scale2X ) { TXT( "\nScale2X : " ); UID( src->SrcRegisterExtMod.Scale2X ); } if( deflt || fs->SrcRegisterExtMod.Absolute != src->SrcRegisterExtMod.Absolute ) { TXT( "\nAbsolute : " ); UID( src->SrcRegisterExtMod.Absolute ); } if( deflt || fs->SrcRegisterExtMod.Negate != src->SrcRegisterExtMod.Negate ) { TXT( "\nNegate : " ); UID( src->SrcRegisterExtMod.Negate ); } if( ignored ) { TXT( "\nPadding : " ); UIX( src->SrcRegisterExtMod.Padding ); if( deflt || fs->SrcRegisterExtMod.Extended != src->SrcRegisterExtMod.Extended ) { TXT( "\nExtended : " ); UID( src->SrcRegisterExtMod.Extended ); } } } } }
static void scan_instruction(struct tgsi_shader_info *info, const struct tgsi_full_instruction *fullinst, unsigned *current_depth) { unsigned i; bool is_mem_inst = false; assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); info->opcode_count[fullinst->Instruction.Opcode]++; switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: case TGSI_OPCODE_BGNLOOP: (*current_depth)++; info->max_depth = MAX2(info->max_depth, *current_depth); break; case TGSI_OPCODE_ENDIF: case TGSI_OPCODE_ENDLOOP: (*current_depth)--; break; default: break; } if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID || fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET || fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) { const struct tgsi_full_src_register *src0 = &fullinst->Src[0]; unsigned input; if (src0->Register.Indirect && src0->Indirect.ArrayID) input = info->input_array_first[src0->Indirect.ArrayID]; else input = src0->Register.Index; /* For the INTERP opcodes, the interpolation is always * PERSPECTIVE unless LINEAR is specified. */ switch (info->input_interpolate[input]) { case TGSI_INTERPOLATE_COLOR: case TGSI_INTERPOLATE_CONSTANT: case TGSI_INTERPOLATE_PERSPECTIVE: switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_INTERP_CENTROID: info->uses_persp_opcode_interp_centroid = TRUE; break; case TGSI_OPCODE_INTERP_OFFSET: info->uses_persp_opcode_interp_offset = TRUE; break; case TGSI_OPCODE_INTERP_SAMPLE: info->uses_persp_opcode_interp_sample = TRUE; break; } break; case TGSI_INTERPOLATE_LINEAR: switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_INTERP_CENTROID: info->uses_linear_opcode_interp_centroid = TRUE; break; case TGSI_OPCODE_INTERP_OFFSET: info->uses_linear_opcode_interp_offset = TRUE; break; case TGSI_OPCODE_INTERP_SAMPLE: info->uses_linear_opcode_interp_sample = TRUE; break; } break; } } if (fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D && fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) info->uses_doubles = TRUE; for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { const struct tgsi_full_src_register *src = &fullinst->Src[i]; int ind = src->Register.Index; /* Mark which inputs are effectively used */ if (src->Register.File == TGSI_FILE_INPUT) { unsigned usage_mask; usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); if (src->Register.Indirect) { for (ind = 0; ind < info->num_inputs; ++ind) { info->input_usage_mask[ind] |= usage_mask; } } else { assert(ind >= 0); assert(ind < PIPE_MAX_SHADER_INPUTS); info->input_usage_mask[ind] |= usage_mask; } if (info->processor == PIPE_SHADER_FRAGMENT && !src->Register.Indirect) { unsigned name = info->input_semantic_name[src->Register.Index]; unsigned index = info->input_semantic_index[src->Register.Index]; if (name == TGSI_SEMANTIC_POSITION && (src->Register.SwizzleX == TGSI_SWIZZLE_Z || src->Register.SwizzleY == TGSI_SWIZZLE_Z || src->Register.SwizzleZ == TGSI_SWIZZLE_Z || src->Register.SwizzleW == TGSI_SWIZZLE_Z)) info->reads_z = TRUE; if (name == TGSI_SEMANTIC_COLOR) { unsigned mask = (1 << src->Register.SwizzleX) | (1 << src->Register.SwizzleY) | (1 << src->Register.SwizzleZ) | (1 << src->Register.SwizzleW); info->colors_read |= mask << (index * 4); } } } /* check for indirect register reads */ if (src->Register.Indirect) { info->indirect_files |= (1 << src->Register.File); info->indirect_files_read |= (1 << src->Register.File); } /* Texture samplers */ if (src->Register.File == TGSI_FILE_SAMPLER) { const unsigned index = src->Register.Index; assert(fullinst->Instruction.Texture); assert(index < ARRAY_SIZE(info->is_msaa_sampler)); assert(index < PIPE_MAX_SAMPLERS); if (is_texture_inst(fullinst->Instruction.Opcode)) { const unsigned target = fullinst->Texture.Texture; assert(target < TGSI_TEXTURE_UNKNOWN); /* for texture instructions, check that the texture instruction * target matches the previous sampler view declaration (if there * was one.) */ if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) { /* probably no sampler view declaration */ info->sampler_targets[index] = target; } else { /* Make sure the texture instruction's sampler/target info * agrees with the sampler view declaration. */ assert(info->sampler_targets[index] == target); } /* MSAA samplers */ if (target == TGSI_TEXTURE_2D_MSAA || target == TGSI_TEXTURE_2D_ARRAY_MSAA) { info->is_msaa_sampler[src->Register.Index] = TRUE; } } } if (is_memory_file(src->Register.File)) { is_mem_inst = true; if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) { info->writes_memory = TRUE; if (src->Register.File == TGSI_FILE_IMAGE && !src->Register.Indirect) info->images_writemask |= 1 << src->Register.Index; } } } /* check for indirect register writes */ for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; if (dst->Register.Indirect) { info->indirect_files |= (1 << dst->Register.File); info->indirect_files_written |= (1 << dst->Register.File); } if (is_memory_file(dst->Register.File)) { assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE); is_mem_inst = true; info->writes_memory = TRUE; if (dst->Register.File == TGSI_FILE_IMAGE && !dst->Register.Indirect) info->images_writemask |= 1 << dst->Register.Index; } } if (is_mem_inst) info->num_memory_instructions++; info->num_instructions++; }
static boolean iter_instruction( struct tgsi_iterate_context *iter, struct tgsi_full_instruction *inst ) { struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; const struct tgsi_opcode_info *info; uint i; if (inst->Instruction.Opcode == TGSI_OPCODE_END) { if (ctx->index_of_END != ~0) { report_error( ctx, "Too many END instructions" ); } ctx->index_of_END = ctx->num_instructions; } info = tgsi_get_opcode_info( inst->Instruction.Opcode ); if (info == NULL) { report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode ); return TRUE; } if (info->num_dst != inst->Instruction.NumDstRegs) { report_error( ctx, "Invalid number of destination operands, should be %u", info->num_dst ); } if (info->num_src != inst->Instruction.NumSrcRegs) { report_error( ctx, "Invalid number of source operands, should be %u", info->num_src ); } /* Check destination and source registers' validity. * Mark the registers as used. */ for (i = 0; i < inst->Instruction.NumDstRegs; i++) { check_register_usage( ctx, inst->FullDstRegisters[i].DstRegister.File, inst->FullDstRegisters[i].DstRegister.Index, "destination", FALSE ); } for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { check_register_usage( ctx, inst->FullSrcRegisters[i].SrcRegister.File, inst->FullSrcRegisters[i].SrcRegister.Index, "source", (boolean)inst->FullSrcRegisters[i].SrcRegister.Indirect ); if (inst->FullSrcRegisters[i].SrcRegister.Indirect) { uint file; int index; file = inst->FullSrcRegisters[i].SrcRegisterInd.File; index = inst->FullSrcRegisters[i].SrcRegisterInd.Index; check_register_usage( ctx, file, index, "indirect", FALSE ); if (file != TGSI_FILE_ADDRESS || index != 0) report_warning( ctx, "Indirect register not ADDR[0]" ); } } ctx->num_instructions++; return TRUE; }
static boolean iter_instruction( struct tgsi_iterate_context *iter, struct tgsi_full_instruction *inst ) { struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; const struct tgsi_opcode_info *info; uint i; if (inst->Instruction.Opcode == TGSI_OPCODE_END) { if (ctx->index_of_END != ~0) { report_error( ctx, "Too many END instructions" ); } ctx->index_of_END = ctx->num_instructions; } info = tgsi_get_opcode_info( inst->Instruction.Opcode ); if (!info) { report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode ); return TRUE; } if (info->num_dst != inst->Instruction.NumDstRegs) { report_error( ctx, "%s: Invalid number of destination operands, should be %u", info->mnemonic, info->num_dst ); } if (info->num_src != inst->Instruction.NumSrcRegs) { report_error( ctx, "%s: Invalid number of source operands, should be %u", info->mnemonic, info->num_src ); } /* Check destination and source registers' validity. * Mark the registers as used. */ for (i = 0; i < inst->Instruction.NumDstRegs; i++) { scan_register *reg = create_scan_register_dst(&inst->Dst[i]); check_register_usage( ctx, reg, "destination", FALSE ); if (!inst->Dst[i].Register.WriteMask) { report_error(ctx, "Destination register has empty writemask"); } } for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { scan_register *reg = create_scan_register_src(&inst->Src[i]); check_register_usage( ctx, reg, "source", (boolean)inst->Src[i].Register.Indirect ); if (inst->Src[i].Register.Indirect) { scan_register *ind_reg = MALLOC(sizeof(scan_register)); fill_scan_register1d(ind_reg, inst->Src[i].Indirect.File, inst->Src[i].Indirect.Index); check_register_usage( ctx, ind_reg, "indirect", FALSE ); } } ctx->num_instructions++; return TRUE; }
static boolean parse_instruction( struct translate_ctx *ctx, boolean has_label ) { uint i; uint saturate = TGSI_SAT_NONE; const struct tgsi_opcode_info *info; struct tgsi_full_instruction inst; uint advance; inst = tgsi_default_full_instruction(); /* Parse predicate. */ eat_opt_white( &ctx->cur ); if (*ctx->cur == '(') { uint file; int index; uint swizzle[4]; boolean parsed_swizzle; inst.Instruction.Predicate = 1; ctx->cur++; if (*ctx->cur == '!') { ctx->cur++; inst.Predicate.Negate = 1; } if (!parse_register_1d( ctx, &file, &index )) return FALSE; if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { if (parsed_swizzle) { inst.Predicate.SwizzleX = swizzle[0]; inst.Predicate.SwizzleY = swizzle[1]; inst.Predicate.SwizzleZ = swizzle[2]; inst.Predicate.SwizzleW = swizzle[3]; } } if (*ctx->cur != ')') { report_error( ctx, "Expected `)'" ); return FALSE; } ctx->cur++; } /* Parse instruction name. */ eat_opt_white( &ctx->cur ); for (i = 0; i < TGSI_OPCODE_LAST; i++) { const char *cur = ctx->cur; info = tgsi_get_opcode_info( i ); if (match_inst_mnemonic(&cur, info)) { if (str_match_no_case( &cur, "_SATNV" )) saturate = TGSI_SAT_MINUS_PLUS_ONE; else if (str_match_no_case( &cur, "_SAT" )) saturate = TGSI_SAT_ZERO_ONE; if (info->num_dst + info->num_src + info->is_tex == 0) { if (!is_digit_alpha_underscore( cur )) { ctx->cur = cur; break; } } else if (*cur == '\0' || eat_white( &cur )) { ctx->cur = cur; break; } } } if (i == TGSI_OPCODE_LAST) { if (has_label) report_error( ctx, "Unknown opcode" ); else report_error( ctx, "Expected `DCL', `IMM' or a label" ); return FALSE; } inst.Instruction.Opcode = i; inst.Instruction.Saturate = saturate; inst.Instruction.NumDstRegs = info->num_dst; inst.Instruction.NumSrcRegs = info->num_src; /* Parse instruction operands. */ for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { if (i > 0) { eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); } if (i < info->num_dst) { if (!parse_dst_operand( ctx, &inst.Dst[i] )) return FALSE; } else if (i < info->num_dst + info->num_src) { if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) return FALSE; } else { uint j; for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { if (str_match_no_case( &ctx->cur, texture_names[j] )) { if (!is_digit_alpha_underscore( ctx->cur )) { inst.Instruction.Texture = 1; inst.Texture.Texture = j; break; } } } if (j == TGSI_TEXTURE_COUNT) { report_error( ctx, "Expected texture target" ); return FALSE; } } } if (info->is_branch) { uint target; eat_opt_white( &ctx->cur ); if (*ctx->cur != ':') { report_error( ctx, "Expected `:'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); if (!parse_uint( &ctx->cur, &target )) { report_error( ctx, "Expected a label" ); return FALSE; } inst.Instruction.Label = 1; inst.Label.Label = target; } advance = tgsi_build_full_instruction( &inst, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }
static boolean parse_instruction( struct translate_ctx *ctx, boolean has_label ) { uint i; uint saturate = 0; uint precise = 0; const struct tgsi_opcode_info *info; struct tgsi_full_instruction inst; const char *cur; uint advance; inst = tgsi_default_full_instruction(); /* Parse instruction name. */ eat_opt_white( &ctx->cur ); for (i = 0; i < TGSI_OPCODE_LAST; i++) { cur = ctx->cur; info = tgsi_get_opcode_info( i ); if (match_inst(&cur, &saturate, &precise, info)) { if (info->num_dst + info->num_src + info->is_tex == 0) { ctx->cur = cur; break; } else if (*cur == '\0' || eat_white( &cur )) { ctx->cur = cur; break; } } } if (i == TGSI_OPCODE_LAST) { if (has_label) report_error( ctx, "Unknown opcode" ); else report_error( ctx, "Expected `DCL', `IMM' or a label" ); return FALSE; } inst.Instruction.Opcode = i; inst.Instruction.Saturate = saturate; inst.Instruction.Precise = precise; inst.Instruction.NumDstRegs = info->num_dst; inst.Instruction.NumSrcRegs = info->num_src; if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) { /* * These are not considered tex opcodes here (no additional * target argument) however we're required to set the Texture * bit so we can set the number of tex offsets. */ inst.Instruction.Texture = 1; inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN; } if ((i >= TGSI_OPCODE_LOAD && i <= TGSI_OPCODE_ATOMIMAX) || i == TGSI_OPCODE_RESQ) { inst.Instruction.Memory = 1; inst.Memory.Qualifier = 0; } assume(info->num_dst <= TGSI_FULL_MAX_DST_REGISTERS); assume(info->num_src <= TGSI_FULL_MAX_SRC_REGISTERS); /* Parse instruction operands. */ for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { if (i > 0) { eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); } if (i < info->num_dst) { if (!parse_dst_operand( ctx, &inst.Dst[i] )) return FALSE; } else if (i < info->num_dst + info->num_src) { if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) return FALSE; } else { uint j; for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) { inst.Instruction.Texture = 1; inst.Texture.Texture = j; break; } } if (j == TGSI_TEXTURE_COUNT) { report_error( ctx, "Expected texture target" ); return FALSE; } } } cur = ctx->cur; eat_opt_white( &cur ); for (i = 0; inst.Instruction.Texture && *cur == ',' && i < TGSI_FULL_MAX_TEX_OFFSETS; i++) { cur++; eat_opt_white( &cur ); ctx->cur = cur; if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] )) return FALSE; cur = ctx->cur; eat_opt_white( &cur ); } inst.Texture.NumOffsets = i; cur = ctx->cur; eat_opt_white(&cur); for (; inst.Instruction.Memory && *cur == ','; ctx->cur = cur, eat_opt_white(&cur)) { int j; cur++; eat_opt_white(&cur); j = str_match_name_from_array(&cur, tgsi_memory_names, ARRAY_SIZE(tgsi_memory_names)); if (j >= 0) { inst.Memory.Qualifier |= 1U << j; continue; } j = str_match_name_from_array(&cur, tgsi_texture_names, ARRAY_SIZE(tgsi_texture_names)); if (j >= 0) { inst.Memory.Texture = j; continue; } j = str_match_format(&cur); if (j >= 0) { inst.Memory.Format = j; continue; } ctx->cur = cur; report_error(ctx, "Expected memory qualifier, texture target, or format\n"); return FALSE; } cur = ctx->cur; eat_opt_white( &cur ); if (info->is_branch && *cur == ':') { uint target; cur++; eat_opt_white( &cur ); if (!parse_uint( &cur, &target )) { report_error( ctx, "Expected a label" ); return FALSE; } inst.Instruction.Label = 1; inst.Label.Label = target; ctx->cur = cur; } advance = tgsi_build_full_instruction( &inst, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }