/* * Direct3D shader assembler * * Copyright 2008 Stefan Dösinger * Copyright 2009 Matteo Bruni * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ %{ #include "config.h" #include "wine/port.h" #include "wine/debug.h" #include "d3dcompiler_private.h" #include <stdio.h> WINE_DEFAULT_DEBUG_CHANNEL(asmshader); struct asm_parser asm_ctx; /* Error reporting function */ void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) { va_list args; char* newbuffer; int rc, newsize; if(ctx->messagecapacity == 0) { ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE); if(ctx->messages == NULL) { ERR("Error allocating memory for parser messages\n"); return; } ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE; } while(1) { va_start(args, fmt); rc = vsnprintf(ctx->messages + ctx->messagesize, ctx->messagecapacity - ctx->messagesize, fmt, args); va_end(args); if (rc < 0 || /* C89 */ rc >= ctx->messagecapacity - ctx->messagesize) { /* C99 */ /* Resize the buffer */ newsize = ctx->messagecapacity * 2; newbuffer = asm_realloc(ctx->messages, newsize); if(newbuffer == NULL){ ERR("Error reallocating memory for parser messages\n"); return; } ctx->messages = newbuffer; ctx->messagecapacity = newsize; } else { ctx->messagesize += rc; return; } } } static void asmshader_error(char const *s) { asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s); set_parse_status(&asm_ctx, PARSE_ERR); } static void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) { /* We can have an additional offset without true relative addressing * ex. c2[ 4 ] */ reg->regnum += rel->additional_offset; if(!rel->has_rel_reg) { reg->rel_reg = NULL; } else { reg->rel_reg = asm_alloc(sizeof(*reg->rel_reg)); if(!reg->rel_reg) { return; } reg->rel_reg->type = rel->type; reg->rel_reg->u.swizzle = rel->swizzle; reg->rel_reg->regnum = rel->rel_regnum; } } /* Needed lexer functions declarations */ int asmshader_lex(void); %} %union { struct { float val; BOOL integer; } immval; BOOL immbool; unsigned int regnum; struct shader_reg reg; DWORD srcmod; DWORD writemask; struct { DWORD writemask; DWORD idx; DWORD last; } wm_components; DWORD swizzle; struct { DWORD swizzle; DWORD idx; } sw_components; DWORD component; struct { DWORD mod; DWORD shift; } modshift; BWRITER_COMPARISON_TYPE comptype; struct { DWORD dclusage; unsigned int regnum; } declaration; BWRITERSAMPLER_TEXTURE_TYPE samplertype; struct rel_reg rel_reg; struct src_regs sregs; } /* Common instructions between vertex and pixel shaders */ %token INSTR_ADD %token INSTR_NOP %token INSTR_MOV %token INSTR_SUB %token INSTR_MAD %token INSTR_MUL %token INSTR_RCP %token INSTR_RSQ %token INSTR_DP3 %token INSTR_DP4 %token INSTR_MIN %token INSTR_MAX %token INSTR_SLT %token INSTR_SGE %token INSTR_ABS %token INSTR_EXP %token INSTR_LOG %token INSTR_EXPP %token INSTR_LOGP %token INSTR_DST %token INSTR_LRP %token INSTR_FRC %token INSTR_POW %token INSTR_CRS %token INSTR_SGN %token INSTR_NRM %token INSTR_SINCOS %token INSTR_M4x4 %token INSTR_M4x3 %token INSTR_M3x4 %token INSTR_M3x3 %token INSTR_M3x2 %token INSTR_DCL %token INSTR_DEF %token INSTR_DEFB %token INSTR_DEFI %token INSTR_REP %token INSTR_ENDREP %token INSTR_IF %token INSTR_ELSE %token INSTR_ENDIF %token INSTR_BREAK %token INSTR_BREAKP %token INSTR_CALL %token INSTR_CALLNZ %token INSTR_LOOP %token INSTR_RET %token INSTR_ENDLOOP %token INSTR_LABEL %token INSTR_SETP %token INSTR_TEXLDL /* Vertex shader only instructions */ %token INSTR_LIT %token INSTR_MOVA /* Pixel shader only instructions */ %token INSTR_CND %token INSTR_CMP %token INSTR_DP2ADD %token INSTR_TEXCOORD %token INSTR_TEXCRD %token INSTR_TEXKILL %token INSTR_TEX %token INSTR_TEXLD %token INSTR_TEXBEM %token INSTR_TEXBEML %token INSTR_TEXREG2AR %token INSTR_TEXREG2GB %token INSTR_TEXREG2RGB %token INSTR_TEXM3x2PAD %token INSTR_TEXM3x2TEX %token INSTR_TEXM3x3PAD %token INSTR_TEXM3x3SPEC %token INSTR_TEXM3x3VSPEC %token INSTR_TEXM3x3TEX %token INSTR_TEXDP3TEX %token INSTR_TEXM3x2DEPTH %token INSTR_TEXDP3 %token INSTR_TEXM3x3 %token INSTR_TEXDEPTH %token INSTR_BEM %token INSTR_DSX %token INSTR_DSY %token INSTR_TEXLDP %token INSTR_TEXLDB %token INSTR_TEXLDD %token INSTR_PHASE /* Registers */ %token <regnum> REG_TEMP %token <regnum> REG_OUTPUT %token <regnum> REG_INPUT %token <regnum> REG_CONSTFLOAT %token <regnum> REG_CONSTINT %token <regnum> REG_CONSTBOOL %token <regnum> REG_TEXTURE %token <regnum> REG_SAMPLER %token <regnum> REG_TEXCRDOUT %token REG_OPOS %token REG_OFOG %token REG_OPTS %token <regnum> REG_VERTEXCOLOR %token <regnum> REG_FRAGCOLOR %token REG_FRAGDEPTH %token REG_VPOS %token REG_VFACE %token REG_ADDRESS %token REG_LOOP %token REG_PREDICATE %token <regnum> REG_LABEL /* Version tokens */ %token VER_VS10 %token VER_VS11 %token VER_VS20 %token VER_VS2X %token VER_VS30 %token VER_PS10 %token VER_PS11 %token VER_PS12 %token VER_PS13 %token VER_PS14 %token VER_PS20 %token VER_PS2X %token VER_PS30 /* Output modifiers */ %token SHIFT_X2 %token SHIFT_X4 %token SHIFT_X8 %token SHIFT_D2 %token SHIFT_D4 %token SHIFT_D8 %token MOD_SAT %token MOD_PP %token MOD_CENTROID /* Compare tokens */ %token COMP_GT %token COMP_LT %token COMP_GE %token COMP_LE %token COMP_EQ %token COMP_NE /* Source register modifiers */ %token SMOD_BIAS %token SMOD_SCALEBIAS %token SMOD_DZ %token SMOD_DW %token SMOD_ABS %token SMOD_NOT /* Sampler types */ %token SAMPTYPE_1D %token SAMPTYPE_2D %token SAMPTYPE_CUBE %token SAMPTYPE_VOLUME /* Usage declaration tokens */ %token <regnum> USAGE_POSITION %token <regnum> USAGE_BLENDWEIGHT %token <regnum> USAGE_BLENDINDICES %token <regnum> USAGE_NORMAL %token <regnum> USAGE_PSIZE %token <regnum> USAGE_TEXCOORD %token <regnum> USAGE_TANGENT %token <regnum> USAGE_BINORMAL %token <regnum> USAGE_TESSFACTOR %token <regnum> USAGE_POSITIONT %token <regnum> USAGE_COLOR %token <regnum> USAGE_FOG %token <regnum> USAGE_DEPTH %token <regnum> USAGE_SAMPLE /* Misc stuff */ %token <component> COMPONENT %token <immval> IMMVAL %token <immbool> IMMBOOL %type <reg> dreg_name %type <reg> dreg %type <reg> sreg_name %type <reg> relreg_name %type <reg> sreg %type <srcmod> smod %type <writemask> writemask %type <wm_components> wm_components %type <swizzle> swizzle %type <sw_components> sw_components %type <modshift> omods %type <modshift> omodifier %type <comptype> comp %type <declaration> dclusage %type <reg> dcl_inputreg %type <samplertype> sampdcl %type <rel_reg> rel_reg %type <reg> predicate %type <immval> immsum %type <sregs> sregs %% shader: version_marker instructions { asm_ctx.funcs->end(&asm_ctx); } version_marker: VER_VS10 { TRACE("Vertex shader 1.0\n"); create_vs10_parser(&asm_ctx); } | VER_VS11 { TRACE("Vertex shader 1.1\n"); create_vs11_parser(&asm_ctx); } | VER_VS20 { TRACE("Vertex shader 2.0\n"); create_vs20_parser(&asm_ctx); } | VER_VS2X { TRACE("Vertex shader 2.x\n"); create_vs2x_parser(&asm_ctx); } | VER_VS30 { TRACE("Vertex shader 3.0\n"); create_vs30_parser(&asm_ctx); } | VER_PS10 { TRACE("Pixel shader 1.0\n"); create_ps10_parser(&asm_ctx); } | VER_PS11 { TRACE("Pixel shader 1.1\n"); create_ps11_parser(&asm_ctx); } | VER_PS12 { TRACE("Pixel shader 1.2\n"); create_ps12_parser(&asm_ctx); } | VER_PS13 { TRACE("Pixel shader 1.3\n"); create_ps13_parser(&asm_ctx); } | VER_PS14 { TRACE("Pixel shader 1.4\n"); create_ps14_parser(&asm_ctx); } | VER_PS20 { TRACE("Pixel shader 2.0\n"); create_ps20_parser(&asm_ctx); } | VER_PS2X { TRACE("Pixel shader 2.x\n"); create_ps2x_parser(&asm_ctx); } | VER_PS30 { TRACE("Pixel shader 3.0\n"); create_ps30_parser(&asm_ctx); } instructions: /* empty */ | instructions complexinstr { /* Nothing to do */ } complexinstr: instruction { } | predicate instruction { TRACE("predicate\n"); asm_ctx.funcs->predicate(&asm_ctx, &$1); } | '+' instruction { TRACE("coissue\n"); asm_ctx.funcs->coissue(&asm_ctx); } instruction: INSTR_ADD omods dreg ',' sregs { TRACE("ADD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_NOP { TRACE("NOP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0); } | INSTR_MOV omods dreg ',' sregs { TRACE("MOV\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_SUB omods dreg ',' sregs { TRACE("SUB\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_MAD omods dreg ',' sregs { TRACE("MAD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_MUL omods dreg ',' sregs { TRACE("MUL\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_RCP omods dreg ',' sregs { TRACE("RCP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_RSQ omods dreg ',' sregs { TRACE("RSQ\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_DP3 omods dreg ',' sregs { TRACE("DP3\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_DP4 omods dreg ',' sregs { TRACE("DP4\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_MIN omods dreg ',' sregs { TRACE("MIN\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_MAX omods dreg ',' sregs { TRACE("MAX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_SLT omods dreg ',' sregs { TRACE("SLT\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_SGE omods dreg ',' sregs { TRACE("SGE\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_ABS omods dreg ',' sregs { TRACE("ABS\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_EXP omods dreg ',' sregs { TRACE("EXP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_LOG omods dreg ',' sregs { TRACE("LOG\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_LOGP omods dreg ',' sregs { TRACE("LOGP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_EXPP omods dreg ',' sregs { TRACE("EXPP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_DST omods dreg ',' sregs { TRACE("DST\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_LRP omods dreg ',' sregs { TRACE("LRP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_FRC omods dreg ',' sregs { TRACE("FRC\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_POW omods dreg ',' sregs { TRACE("POW\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_CRS omods dreg ',' sregs { TRACE("CRS\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_SGN omods dreg ',' sregs { TRACE("SGN\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_NRM omods dreg ',' sregs { TRACE("NRM\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_SINCOS omods dreg ',' sregs { TRACE("SINCOS\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_M4x4 omods dreg ',' sregs { TRACE("M4x4\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_M4x3 omods dreg ',' sregs { TRACE("M4x3\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_M3x4 omods dreg ',' sregs { TRACE("M3x4\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_M3x3 omods dreg ',' sregs { TRACE("M3x3\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_M3x2 omods dreg ',' sregs { TRACE("M3x2\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_DCL dclusage REG_OUTPUT { struct shader_reg reg; TRACE("Output reg declaration\n"); ZeroMemory(®, sizeof(reg)); reg.type = BWRITERSPR_OUTPUT; reg.regnum = $3; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = BWRITERSP_WRITEMASK_ALL; asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); } | INSTR_DCL dclusage REG_OUTPUT writemask { struct shader_reg reg; TRACE("Output reg declaration\n"); ZeroMemory(®, sizeof(reg)); reg.type = BWRITERSPR_OUTPUT; reg.regnum = $3; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = $4; asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); } | INSTR_DCL dclusage omods dcl_inputreg { struct shader_reg reg; TRACE("Input reg declaration\n"); if($3.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } if(asm_ctx.shader->version == BWRITERPS_VERSION(2, 0) || asm_ctx.shader->version == BWRITERPS_VERSION(2, 1)) { asmparser_message(&asm_ctx, "Line %u: Declaration not supported in PS 2\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } ZeroMemory(®, sizeof(reg)); reg.type = $4.type; reg.regnum = $4.regnum; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = BWRITERSP_WRITEMASK_ALL; asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®); } | INSTR_DCL dclusage omods dcl_inputreg writemask { struct shader_reg reg; TRACE("Input reg declaration\n"); if($3.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } if(asm_ctx.shader->version == BWRITERPS_VERSION(2, 0) || asm_ctx.shader->version == BWRITERPS_VERSION(2, 1)) { asmparser_message(&asm_ctx, "Line %u: Declaration not supported in PS 2\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } ZeroMemory(®, sizeof(reg)); reg.type = $4.type; reg.regnum = $4.regnum; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = $5; asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®); } | INSTR_DCL omods dcl_inputreg { struct shader_reg reg; TRACE("Input reg declaration\n"); if($2.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } if(asm_ctx.shader->type != ST_PIXEL) { asmparser_message(&asm_ctx, "Line %u: Declaration needs a semantic\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } ZeroMemory(®, sizeof(reg)); reg.type = $3.type; reg.regnum = $3.regnum; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = BWRITERSP_WRITEMASK_ALL; asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®); } | INSTR_DCL omods dcl_inputreg writemask { struct shader_reg reg; TRACE("Input reg declaration\n"); if($2.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } if(asm_ctx.shader->type != ST_PIXEL) { asmparser_message(&asm_ctx, "Line %u: Declaration needs a semantic\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } ZeroMemory(®, sizeof(reg)); reg.type = $3.type; reg.regnum = $3.regnum; reg.rel_reg = NULL; reg.srcmod = 0; reg.u.writemask = $4; asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®); } | INSTR_DCL sampdcl omods REG_SAMPLER { TRACE("Sampler declared\n"); if($3.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3.mod, $4, asm_ctx.line_no); } | INSTR_DCL omods REG_SAMPLER { TRACE("Sampler declared\n"); if($2.shift != 0) { asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } if(asm_ctx.shader->type != ST_PIXEL) { asmparser_message(&asm_ctx, "Line %u: Declaration needs a sampler type\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } asm_ctx.funcs->dcl_sampler(&asm_ctx, BWRITERSTT_UNKNOWN, $2.mod, $3, asm_ctx.line_no); } | INSTR_DCL sampdcl omods dcl_inputreg { TRACE("Error rule: sampler decl of input reg\n"); asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | INSTR_DCL sampdcl omods REG_OUTPUT { TRACE("Error rule: sampler decl of output reg\n"); asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL { asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val); } | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL { asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val); } | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL { asm_ctx.funcs->constB(&asm_ctx, $2, $4); } | INSTR_REP sregs { TRACE("REP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1); } | INSTR_ENDREP { TRACE("ENDREP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0); } | INSTR_IF sregs { TRACE("IF\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1); } | INSTR_IF comp sregs { TRACE("IFC\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2); } | INSTR_ELSE { TRACE("ELSE\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0); } | INSTR_ENDIF { TRACE("ENDIF\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0); } | INSTR_BREAK { TRACE("BREAK\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0); } | INSTR_BREAK comp sregs { TRACE("BREAKC\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2); } | INSTR_BREAKP sregs { TRACE("BREAKP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1); } | INSTR_CALL sregs { TRACE("CALL\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1); } | INSTR_CALLNZ sregs { TRACE("CALLNZ\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2); } | INSTR_LOOP sregs { TRACE("LOOP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2); } | INSTR_RET { TRACE("RET\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0); } | INSTR_ENDLOOP { TRACE("ENDLOOP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0); } | INSTR_LABEL sregs { TRACE("LABEL\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1); } | INSTR_SETP comp dreg ',' sregs { TRACE("SETP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2); } | INSTR_TEXLDL omods dreg ',' sregs { TRACE("TEXLDL\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_LIT omods dreg ',' sregs { TRACE("LIT\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_MOVA omods dreg ',' sregs { TRACE("MOVA\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_CND omods dreg ',' sregs { TRACE("CND\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CND, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_CMP omods dreg ',' sregs { TRACE("CMP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_DP2ADD omods dreg ',' sregs { TRACE("DP2ADD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3); } | INSTR_TEXCOORD omods dreg { TRACE("TEXCOORD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXCOORD, $2.mod, $2.shift, 0, &$3, 0, 0); } | INSTR_TEXCRD omods dreg ',' sregs { TRACE("TEXCRD\n"); /* texcoord and texcrd share the same opcode */ asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXCOORD, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXKILL dreg { TRACE("TEXKILL\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXKILL, 0, 0, 0, &$2, 0, 0); } | INSTR_TEX omods dreg { TRACE("TEX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, 0, 0); } | INSTR_TEXDEPTH omods dreg { TRACE("TEXDEPTH\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXDEPTH, $2.mod, $2.shift, 0, &$3, 0, 0); } | INSTR_TEXLD omods dreg ',' sregs { TRACE("TEXLD\n"); /* There is more than one acceptable syntax for texld: with 1 sreg (PS 1.4) or with 2 sregs (PS 2.0+) Moreover, texld shares the same opcode as the tex instruction, so there are a total of 3 valid syntaxes These variations are handled in asmparser.c */ asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_TEXLDP omods dreg ',' sregs { TRACE("TEXLDP\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDP, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_TEXLDB omods dreg ',' sregs { TRACE("TEXLDB\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDB, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_TEXBEM omods dreg ',' sregs { TRACE("TEXBEM\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXBEM, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXBEML omods dreg ',' sregs { TRACE("TEXBEML\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXBEML, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXREG2AR omods dreg ',' sregs { TRACE("TEXREG2AR\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXREG2AR, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXREG2GB omods dreg ',' sregs { TRACE("TEXREG2GB\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXREG2GB, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXREG2RGB omods dreg ',' sregs { TRACE("TEXREG2RGB\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXREG2RGB, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x2PAD omods dreg ',' sregs { TRACE("TEXM3x2PAD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x2PAD, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x3PAD omods dreg ',' sregs { TRACE("INSTR_TEXM3x3PAD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x3PAD, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x3SPEC omods dreg ',' sregs { TRACE("TEXM3x3SPEC\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x3SPEC, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_TEXM3x3VSPEC omods dreg ',' sregs { TRACE("TEXM3x3VSPEC\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x3VSPEC, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x3TEX omods dreg ',' sregs { TRACE("TEXM3x3TEX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x3TEX, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXDP3TEX omods dreg ',' sregs { TRACE("TEXDP3TEX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXDP3TEX, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x2DEPTH omods dreg ',' sregs { TRACE("TEXM3x2DEPTH\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x2DEPTH, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x2TEX omods dreg ',' sregs { TRACE("TEXM3x2TEX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x2TEX, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXDP3 omods dreg ',' sregs { TRACE("TEXDP3\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXDP3, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXM3x3 omods dreg ',' sregs { TRACE("TEXM3x3\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXM3x3, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_BEM omods dreg ',' sregs { TRACE("BEM\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BEM, $2.mod, $2.shift, 0, &$3, &$5, 2); } | INSTR_DSX omods dreg ',' sregs { TRACE("DSX\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_DSY omods dreg ',' sregs { TRACE("DSY\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1); } | INSTR_TEXLDD omods dreg ',' sregs { TRACE("TEXLDD\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4); } | INSTR_PHASE { TRACE("PHASE\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_PHASE, 0, 0, 0, 0, 0, 0); } dreg: dreg_name rel_reg { $$.regnum = $1.regnum; $$.type = $1.type; $$.u.writemask = BWRITERSP_WRITEMASK_ALL; $$.srcmod = BWRITERSPSM_NONE; set_rel_reg(&$$, &$2); } | dreg_name writemask { $$.regnum = $1.regnum; $$.type = $1.type; $$.u.writemask = $2; $$.srcmod = BWRITERSPSM_NONE; $$.rel_reg = NULL; } dreg_name: REG_TEMP { $$.regnum = $1; $$.type = BWRITERSPR_TEMP; } | REG_OUTPUT { $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT; } | REG_INPUT { $$.regnum = $1; $$.type = BWRITERSPR_INPUT; } | REG_CONSTFLOAT { asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_CONSTINT { asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_CONSTBOOL { asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_TEXTURE { $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE; } | REG_TEXCRDOUT { $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT; } | REG_SAMPLER { asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_OPOS { $$.regnum = BWRITERSRO_POSITION; $$.type = BWRITERSPR_RASTOUT; } | REG_OPTS { $$.regnum = BWRITERSRO_POINT_SIZE; $$.type = BWRITERSPR_RASTOUT; } | REG_OFOG { $$.regnum = BWRITERSRO_FOG; $$.type = BWRITERSPR_RASTOUT; } | REG_VERTEXCOLOR { $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT; } | REG_FRAGCOLOR { $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT; } | REG_FRAGDEPTH { $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT; } | REG_PREDICATE { $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE; } | REG_VPOS { asmparser_message(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_VFACE { asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_ADDRESS { /* index 0 is hardcoded for the addr register */ $$.regnum = 0; $$.type = BWRITERSPR_ADDR; } | REG_LOOP { asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } writemask: '.' wm_components { if($2.writemask == SWIZZLE_ERR) { asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); /* Provide a correct writemask to prevent following complaints */ $$ = BWRITERSP_WRITEMASK_ALL; } else { $$ = $2.writemask; TRACE("Writemask: %x\n", $$); } } wm_components: COMPONENT { $$.writemask = 1 << $1; $$.last = $1; $$.idx = 1; } | wm_components COMPONENT { if($1.writemask == SWIZZLE_ERR || $1.idx == 4) /* Wrong writemask */ $$.writemask = SWIZZLE_ERR; else { if($2 <= $1.last) $$.writemask = SWIZZLE_ERR; else { $$.writemask = $1.writemask | (1 << $2); $$.idx = $1.idx + 1; } } } swizzle: /* empty */ { $$ = BWRITERVS_NOSWIZZLE; TRACE("Default swizzle: %08x\n", $$); } | '.' sw_components { if($2.swizzle == SWIZZLE_ERR) { asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); /* Provide a correct swizzle to prevent following complaints */ $$ = BWRITERVS_NOSWIZZLE; } else { DWORD last, i; $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT; /* Fill the swizzle by extending the last component */ last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03; for(i = $2.idx; i < 4; i++){ $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i); } TRACE("Got a swizzle: %08x\n", $$); } } sw_components: COMPONENT { $$.swizzle = $1; $$.idx = 1; } | sw_components COMPONENT { if($1.idx == 4) { /* Too many sw_components */ $$.swizzle = SWIZZLE_ERR; $$.idx = 4; } else { $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx); $$.idx = $1.idx + 1; } } omods: /* Empty */ { $$.mod = 0; $$.shift = 0; } | omods omodifier { $$.mod = $1.mod | $2.mod; if($1.shift && $2.shift) { asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); $$.shift = $1.shift; } else { $$.shift = $1.shift | $2.shift; } } omodifier: SHIFT_X2 { $$.mod = 0; $$.shift = 1; } | SHIFT_X4 { $$.mod = 0; $$.shift = 2; } | SHIFT_X8 { $$.mod = 0; $$.shift = 3; } | SHIFT_D2 { $$.mod = 0; $$.shift = 15; } | SHIFT_D4 { $$.mod = 0; $$.shift = 14; } | SHIFT_D8 { $$.mod = 0; $$.shift = 13; } | MOD_SAT { $$.mod = BWRITERSPDM_SATURATE; $$.shift = 0; } | MOD_PP { $$.mod = BWRITERSPDM_PARTIALPRECISION; $$.shift = 0; } | MOD_CENTROID { $$.mod = BWRITERSPDM_MSAMPCENTROID; $$.shift = 0; } sregs: sreg { $$.reg[0] = $1; $$.count = 1; } | sregs ',' sreg { if($$.count == MAX_SRC_REGS){ asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } else $$.reg[$$.count++] = $3; } sreg: sreg_name rel_reg swizzle { $$.type = $1.type; $$.regnum = $1.regnum; $$.u.swizzle = $3; $$.srcmod = BWRITERSPSM_NONE; set_rel_reg(&$$, &$2); } | sreg_name rel_reg smod swizzle { $$.type = $1.type; $$.regnum = $1.regnum; set_rel_reg(&$$, &$2); $$.srcmod = $3; $$.u.swizzle = $4; } | '-' sreg_name rel_reg swizzle { $$.type = $2.type; $$.regnum = $2.regnum; $$.srcmod = BWRITERSPSM_NEG; set_rel_reg(&$$, &$3); $$.u.swizzle = $4; } | '-' sreg_name rel_reg smod swizzle { $$.type = $2.type; $$.regnum = $2.regnum; set_rel_reg(&$$, &$3); switch($4) { case BWRITERSPSM_BIAS: $$.srcmod = BWRITERSPSM_BIASNEG; break; case BWRITERSPSM_X2: $$.srcmod = BWRITERSPSM_X2NEG; break; case BWRITERSPSM_SIGN: $$.srcmod = BWRITERSPSM_SIGNNEG; break; case BWRITERSPSM_ABS: $$.srcmod = BWRITERSPSM_ABSNEG; break; case BWRITERSPSM_DZ: asmparser_message(&asm_ctx, "Line %u: Incompatible source modifiers: NEG and DZ\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); break; case BWRITERSPSM_DW: asmparser_message(&asm_ctx, "Line %u: Incompatible source modifiers: NEG and DW\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); break; default: FIXME("Unhandled combination of NEGATE and %u\n", $4); } $$.u.swizzle = $5; } | IMMVAL '-' sreg_name rel_reg swizzle { if($1.val != 1.0 || (!$1.integer)) { asmparser_message(&asm_ctx, "Line %u: Only \"1 - reg\" is valid for D3DSPSM_COMP, " "%g - reg found\n", asm_ctx.line_no, $1.val); set_parse_status(&asm_ctx, PARSE_ERR); } /* Complement - not compatible with other source modifiers */ $$.type = $3.type; $$.regnum = $3.regnum; $$.srcmod = BWRITERSPSM_COMP; set_rel_reg(&$$, &$4); $$.u.swizzle = $5; } | IMMVAL '-' sreg_name rel_reg smod swizzle { /* For nicer error reporting */ if($1.val != 1.0 || (!$1.integer)) { asmparser_message(&asm_ctx, "Line %u: Only \"1 - reg\" is valid for D3DSPSM_COMP\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_ERR); } else { asmparser_message(&asm_ctx, "Line %u: Incompatible source modifiers: D3DSPSM_COMP and %s\n", asm_ctx.line_no, debug_print_srcmod($5)); set_parse_status(&asm_ctx, PARSE_ERR); } } | SMOD_NOT sreg_name swizzle { $$.type = $2.type; $$.regnum = $2.regnum; $$.rel_reg = NULL; $$.srcmod = BWRITERSPSM_NOT; $$.u.swizzle = $3; } rel_reg: /* empty */ { $$.has_rel_reg = FALSE; $$.additional_offset = 0; } | '[' immsum ']' { $$.has_rel_reg = FALSE; $$.additional_offset = $2.val; } | '[' relreg_name swizzle ']' { $$.has_rel_reg = TRUE; $$.type = $2.type; $$.additional_offset = 0; $$.rel_regnum = $2.regnum; $$.swizzle = $3; } | '[' immsum '+' relreg_name swizzle ']' { $$.has_rel_reg = TRUE; $$.type = $4.type; $$.additional_offset = $2.val; $$.rel_regnum = $4.regnum; $$.swizzle = $5; } | '[' relreg_name swizzle '+' immsum ']' { $$.has_rel_reg = TRUE; $$.type = $2.type; $$.additional_offset = $5.val; $$.rel_regnum = $2.regnum; $$.swizzle = $3; } | '[' immsum '+' relreg_name swizzle '+' immsum ']' { $$.has_rel_reg = TRUE; $$.type = $4.type; $$.additional_offset = $2.val + $7.val; $$.rel_regnum = $4.regnum; $$.swizzle = $5; } immsum: IMMVAL { if(!$1.integer) { asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n", asm_ctx.line_no, $1.val); set_parse_status(&asm_ctx, PARSE_ERR); } $$.val = $1.val; } | immsum '+' IMMVAL { if(!$3.integer) { asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n", asm_ctx.line_no, $3.val); set_parse_status(&asm_ctx, PARSE_ERR); } $$.val = $1.val + $3.val; } smod: SMOD_BIAS { $$ = BWRITERSPSM_BIAS; } | SHIFT_X2 { $$ = BWRITERSPSM_X2; } | SMOD_SCALEBIAS { $$ = BWRITERSPSM_SIGN; } | SMOD_DZ { $$ = BWRITERSPSM_DZ; } | SMOD_DW { $$ = BWRITERSPSM_DW; } | SMOD_ABS { $$ = BWRITERSPSM_ABS; } relreg_name: REG_ADDRESS { $$.regnum = 0; $$.type = BWRITERSPR_ADDR; } | REG_LOOP { $$.regnum = 0; $$.type = BWRITERSPR_LOOP; } sreg_name: REG_TEMP { $$.regnum = $1; $$.type = BWRITERSPR_TEMP; } | REG_OUTPUT { asmparser_message(&asm_ctx, "Line %u: Register o%u is not a valid source register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_INPUT { $$.regnum = $1; $$.type = BWRITERSPR_INPUT; } | REG_CONSTFLOAT { $$.regnum = $1; $$.type = BWRITERSPR_CONST; } | REG_CONSTINT { $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT; } | REG_CONSTBOOL { $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL; } | REG_TEXTURE { $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE; } | REG_TEXCRDOUT { asmparser_message(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_SAMPLER { $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER; } | REG_OPOS { asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_OFOG { asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_VERTEXCOLOR { asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_FRAGCOLOR { asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n", asm_ctx.line_no, $1); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_FRAGDEPTH { asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n", asm_ctx.line_no); set_parse_status(&asm_ctx, PARSE_WARN); } | REG_PREDICATE { $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE; } | REG_VPOS { $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE; } | REG_VFACE { $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE; } | REG_ADDRESS { $$.regnum = 0; $$.type = BWRITERSPR_ADDR; } | REG_LOOP { $$.regnum = 0; $$.type = BWRITERSPR_LOOP; } | REG_LABEL { $$.regnum = $1; $$.type = BWRITERSPR_LABEL; } comp: COMP_GT { $$ = BWRITER_COMPARISON_GT; } | COMP_LT { $$ = BWRITER_COMPARISON_LT; } | COMP_GE { $$ = BWRITER_COMPARISON_GE; } | COMP_LE { $$ = BWRITER_COMPARISON_LE; } | COMP_EQ { $$ = BWRITER_COMPARISON_EQ; } | COMP_NE { $$ = BWRITER_COMPARISON_NE; } dclusage: USAGE_POSITION { TRACE("dcl_position%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_POSITION; } | USAGE_BLENDWEIGHT { TRACE("dcl_blendweight%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT; } | USAGE_BLENDINDICES { TRACE("dcl_blendindices%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES; } | USAGE_NORMAL { TRACE("dcl_normal%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_NORMAL; } | USAGE_PSIZE { TRACE("dcl_psize%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_PSIZE; } | USAGE_TEXCOORD { TRACE("dcl_texcoord%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_TEXCOORD; } | USAGE_TANGENT { TRACE("dcl_tangent%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_TANGENT; } | USAGE_BINORMAL { TRACE("dcl_binormal%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_BINORMAL; } | USAGE_TESSFACTOR { TRACE("dcl_tessfactor%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR; } | USAGE_POSITIONT { TRACE("dcl_positiont%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_POSITIONT; } | USAGE_COLOR { TRACE("dcl_color%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_COLOR; } | USAGE_FOG { TRACE("dcl_fog%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_FOG; } | USAGE_DEPTH { TRACE("dcl_depth%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_DEPTH; } | USAGE_SAMPLE { TRACE("dcl_sample%u\n", $1); $$.regnum = $1; $$.dclusage = BWRITERDECLUSAGE_SAMPLE; } dcl_inputreg: REG_INPUT { $$.regnum = $1; $$.type = BWRITERSPR_INPUT; } | REG_TEXTURE { $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE; } sampdcl: SAMPTYPE_1D { $$ = BWRITERSTT_1D; } | SAMPTYPE_2D { $$ = BWRITERSTT_2D; } | SAMPTYPE_CUBE { $$ = BWRITERSTT_CUBE; } | SAMPTYPE_VOLUME { $$ = BWRITERSTT_VOLUME; } predicate: '(' REG_PREDICATE swizzle ')' { $$.type = BWRITERSPR_PREDICATE; $$.regnum = 0; $$.rel_reg = NULL; $$.srcmod = BWRITERSPSM_NONE; $$.u.swizzle = $3; } | '(' SMOD_NOT REG_PREDICATE swizzle ')' { $$.type = BWRITERSPR_PREDICATE; $$.regnum = 0; $$.rel_reg = NULL; $$.srcmod = BWRITERSPSM_NOT; $$.u.swizzle = $4; } %% /* New status is the worst between current status and parameter value */ void set_parse_status(struct asm_parser *ctx, enum parse_status status) { if(status == PARSE_ERR) ctx->status = PARSE_ERR; else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN; } struct bwriter_shader *parse_asm_shader(char **messages) { struct bwriter_shader *ret = NULL; asm_ctx.shader = NULL; asm_ctx.status = PARSE_SUCCESS; asm_ctx.messagesize = asm_ctx.messagecapacity = 0; asm_ctx.line_no = 1; asmshader_parse(); if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader; else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader); if(messages) { if(asm_ctx.messagesize) { /* Shrink the buffer to the used size */ *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1); if(!*messages) { ERR("Out of memory, no messages reported\n"); asm_free(asm_ctx.messages); } } else { *messages = NULL; } } else { if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages); } return ret; }