asmparser.c 54.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Direct3D asm shader parser
 *
 * 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 "wine/debug.h"

25
#include "d3dcompiler_private.h"
26 27 28 29 30

WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
WINE_DECLARE_DEBUG_CHANNEL(parsed_shader);


31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
/* How to map vs 1.0 and 2.0 varyings to 3.0 ones
 * oTx is mapped to ox, which happens to be an
 * identical mapping since BWRITERSPR_TEXCRDOUT == BWRITERSPR_OUTPUT
 * oPos, oFog and point size are mapped to general output regs as well.
 * the vs 1.x and 2.x parser functions add varying declarations
 * to the shader, and the 1.x and 2.x output functions check those varyings
 */
#define OT0_REG         0
#define OT1_REG         1
#define OT2_REG         2
#define OT3_REG         3
#define OT4_REG         4
#define OT5_REG         5
#define OT6_REG         6
#define OT7_REG         7
#define OPOS_REG        8
#define OFOG_REG        9
#define OFOG_WRITEMASK  BWRITERSP_WRITEMASK_0
#define OPTS_REG        9
#define OPTS_WRITEMASK  BWRITERSP_WRITEMASK_1
#define OD0_REG         10
#define OD1_REG         11

54 55 56 57 58 59 60 61 62 63 64
/* Input color registers 0-1 are identically mapped */
#define C0_VARYING      0
#define C1_VARYING      1
#define T0_VARYING      2
#define T1_VARYING      3
#define T2_VARYING      4
#define T3_VARYING      5
#define T4_VARYING      6
#define T5_VARYING      7
#define T6_VARYING      8
#define T7_VARYING      9
65

66 67 68 69 70 71 72 73
/****************************************************************
 * Common(non-version specific) shader parser control code      *
 ****************************************************************/

static void asmparser_end(struct asm_parser *This) {
    TRACE("Finalizing shader\n");
}

74 75 76 77 78 79
static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) {
    if(!This->shader) return;
    TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf);
    TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w);
    if(!add_constF(This->shader, reg, x, y, z, w)) {
        ERR("Out of memory\n");
80
        set_parse_status(&This->status, PARSE_ERR);
81 82 83
    }
}

84 85 86 87 88 89
static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) {
    if(!This->shader) return;
    TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb);
    TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false");
    if(!add_constB(This->shader, reg, x)) {
        ERR("Out of memory\n");
90
        set_parse_status(&This->status, PARSE_ERR);
91 92 93
    }
}

94 95 96 97 98 99
static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) {
    if(!This->shader) return;
    TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci);
    TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w);
    if(!add_constI(This->shader, reg, x, y, z, w)) {
        ERR("Out of memory\n");
100
        set_parse_status(&This->status, PARSE_ERR);
101 102 103
    }
}

104 105 106 107 108
static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num,
                                 const struct shader_reg *reg) {
    if(!This->shader) return;
    if(This->shader->type == ST_PIXEL) {
        asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no);
109
        set_parse_status(&This->status, PARSE_ERR);
110
    }
111
    if(!record_declaration(This->shader, usage, num, 0, TRUE, reg->regnum, reg->u.writemask, FALSE)) {
112
        ERR("Out of memory\n");
113
        set_parse_status(&This->status, PARSE_ERR);
114 115 116
    }
}

117 118 119
static void asmparser_dcl_output_unsupported(struct asm_parser *This, DWORD usage, DWORD num,
                                             const struct shader_reg *reg) {
    asmparser_message(This, "Line %u: Output declaration unsupported in this shader version\n", This->line_no);
120
    set_parse_status(&This->status, PARSE_ERR);
121 122
}

123
static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num,
124
                                DWORD mod, const struct shader_reg *reg) {
125 126
    struct instruction instr;

127
    if(!This->shader) return;
128 129 130
    if (mod && (This->shader->type != ST_PIXEL || This->shader->major_version != 3
            || (mod != BWRITERSPDM_MSAMPCENTROID && mod != BWRITERSPDM_PARTIALPRECISION)))
    {
131
        asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
132
        set_parse_status(&This->status, PARSE_ERR);
133 134
        return;
    }
135 136 137 138 139 140

    /* Check register type and modifiers */
    instr.dstmod = mod;
    instr.shift = 0;
    This->funcs->dstreg(This, &instr, reg);

141
    if(!record_declaration(This->shader, usage, num, mod, FALSE, reg->regnum, reg->u.writemask, FALSE)) {
142
        ERR("Out of memory\n");
143
        set_parse_status(&This->status, PARSE_ERR);
144 145 146
    }
}

147 148 149 150 151 152 153 154
static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD num,
                                     DWORD mod, const struct shader_reg *reg) {
    struct instruction instr;

    if(!This->shader) return;
    instr.dstmod = mod;
    instr.shift = 0;
    This->funcs->dstreg(This, &instr, reg);
155
    if(!record_declaration(This->shader, usage, num, mod, FALSE, instr.dst.regnum, instr.dst.u.writemask, FALSE)) {
156
        ERR("Out of memory\n");
157
        set_parse_status(&This->status, PARSE_ERR);
158 159 160
    }
}

161 162 163
static void asmparser_dcl_input_unsupported(struct asm_parser *This,
        DWORD usage, DWORD num, DWORD mod, const struct shader_reg *reg)
{
164
    asmparser_message(This, "Line %u: Input declaration unsupported in this shader version\n", This->line_no);
165
    set_parse_status(&This->status, PARSE_ERR);
166 167
}

168 169 170
static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype,
                                  DWORD mod, DWORD regnum,
                                  unsigned int line_no) {
171
    if(!This->shader) return;
172 173 174
    if (mod && (This->shader->type != ST_PIXEL || This->shader->major_version != 3
            || (mod != BWRITERSPDM_MSAMPCENTROID && mod != BWRITERSPDM_PARTIALPRECISION)))
    {
175
        asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
176
        set_parse_status(&This->status, PARSE_ERR);
177 178 179
        return;
    }
    if(!record_sampler(This->shader, samptype, mod, regnum)) {
180
        ERR("Out of memory\n");
181
        set_parse_status(&This->status, PARSE_ERR);
182 183 184
    }
}

185 186 187
static void asmparser_dcl_sampler_unsupported(struct asm_parser *This,
        DWORD samptype, DWORD mod, DWORD regnum, unsigned int line_no)
{
188
    asmparser_message(This, "Line %u: Sampler declaration unsupported in this shader version\n", This->line_no);
189
    set_parse_status(&This->status, PARSE_ERR);
190 191
}

192 193 194 195 196 197 198
static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
                             const struct shader_reg *dst,
                             const struct src_regs *srcs) {
    struct instruction *instr;

    if(!srcs || srcs->count != 3) {
        asmparser_message(This, "Line %u: sincos (vs 2) has an incorrect number of source registers\n", This->line_no);
199
        set_parse_status(&This->status, PARSE_ERR);
200 201 202 203 204 205
        return;
    }

    instr = alloc_instr(3);
    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
206
        set_parse_status(&This->status, PARSE_ERR);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
        return;
    }

    instr->opcode = BWRITERSIO_SINCOS;
    instr->dstmod = mod;
    instr->shift = shift;
    instr->comptype = 0;

    This->funcs->dstreg(This, instr, dst);
    This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
    This->funcs->srcreg(This, instr, 1, &srcs->reg[1]);
    This->funcs->srcreg(This, instr, 2, &srcs->reg[2]);

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
222
        set_parse_status(&This->status, PARSE_ERR);
223 224 225
    }
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
    struct shader_reg ret;
    switch(reg->type) {
        case BWRITERSPR_TEXTURE:
            if(tex_varying) {
                ret = *reg;
                ret.type = BWRITERSPR_INPUT;
                switch(reg->regnum) {
                    case 0:     ret.regnum = T0_VARYING; break;
                    case 1:     ret.regnum = T1_VARYING; break;
                    case 2:     ret.regnum = T2_VARYING; break;
                    case 3:     ret.regnum = T3_VARYING; break;
                    case 4:     ret.regnum = T4_VARYING; break;
                    case 5:     ret.regnum = T5_VARYING; break;
                    case 6:     ret.regnum = T6_VARYING; break;
                    case 7:     ret.regnum = T7_VARYING; break;
                    default:
                        FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
                        return *reg;
                }
                return ret;
            } else {
                ret = *reg;
                ret.type = BWRITERSPR_TEMP;
                switch(reg->regnum) {
                    case 0:     ret.regnum = T0_REG; break;
                    case 1:     ret.regnum = T1_REG; break;
                    case 2:     ret.regnum = T2_REG; break;
                    case 3:     ret.regnum = T3_REG; break;
                    default:
                        FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
                        return *reg;
                }
                return ret;
            }

        /* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
           to 3.0 ones */

        default: return *reg;
    }
}

static void asmparser_texcoord(struct asm_parser *This, DWORD mod, DWORD shift,
                               const struct shader_reg *dst,
                               const struct src_regs *srcs) {
    struct instruction *instr;

    if(srcs) {
        asmparser_message(This, "Line %u: Source registers in texcoord instruction\n", This->line_no);
276
        set_parse_status(&This->status, PARSE_ERR);
277 278 279 280 281 282
        return;
    }

    instr = alloc_instr(1);
    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
283
        set_parse_status(&This->status, PARSE_ERR);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
        return;
    }

    /* texcoord copies the texture coord data into a temporary register-like
     * readable form. In newer shader models this equals a MOV from v0 to r0,
     * record it as this.
     */
    instr->opcode = BWRITERSIO_MOV;
    instr->dstmod = mod | BWRITERSPDM_SATURATE; /* texcoord clamps to [0;1] */
    instr->shift = shift;
    instr->comptype = 0;

    This->funcs->dstreg(This, instr, dst);
    /* The src reg needs special care */
    instr->src[0] = map_oldps_register(dst, TRUE);

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
302
        set_parse_status(&This->status, PARSE_ERR);
303 304 305
    }
}

306 307 308 309 310 311 312
static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
                             const struct shader_reg *dst,
                             const struct src_regs *srcs) {
    struct instruction *instr;

    if(!srcs || srcs->count != 1) {
        asmparser_message(This, "Line %u: Wrong number of source registers in texcrd instruction\n", This->line_no);
313
        set_parse_status(&This->status, PARSE_ERR);
314 315 316 317 318 319
        return;
    }

    instr = alloc_instr(1);
    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
320
        set_parse_status(&This->status, PARSE_ERR);
321 322 323 324 325 326 327 328 329 330 331 332 333 334
        return;
    }

    /* The job of texcrd is done by mov in later shader versions */
    instr->opcode = BWRITERSIO_MOV;
    instr->dstmod = mod;
    instr->shift = shift;
    instr->comptype = 0;

    This->funcs->dstreg(This, instr, dst);
    This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
335
        set_parse_status(&This->status, PARSE_ERR);
336 337 338
    }
}

339 340 341 342 343 344
static void asmparser_texkill(struct asm_parser *This,
                              const struct shader_reg *dst) {
    struct instruction *instr = alloc_instr(0);

    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
345
        set_parse_status(&This->status, PARSE_ERR);
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
        return;
    }

    instr->opcode = BWRITERSIO_TEXKILL;
    instr->dstmod = 0;
    instr->shift = 0;
    instr->comptype = 0;

    /* Do not run the dst register through the normal
     * register conversion. If used with ps_1_0 to ps_1_3
     * the texture coordinate from that register is used,
     * not the temporary register value. In ps_1_4 and
     * ps_2_0 t0 is always a varying and temporaries can
     * be used with texkill.
     */
    instr->dst = map_oldps_register(dst, TRUE);
    instr->has_dst = TRUE;

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
366
        set_parse_status(&This->status, PARSE_ERR);
367 368 369 370 371 372 373 374 375 376
    }
}

static void asmparser_texhelper(struct asm_parser *This, DWORD mod, DWORD shift,
                                const struct shader_reg *dst,
                                const struct shader_reg *src0) {
    struct instruction *instr = alloc_instr(2);

    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
377
        set_parse_status(&This->status, PARSE_ERR);
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
        return;
    }

    instr->opcode = BWRITERSIO_TEX;
    instr->dstmod = mod;
    instr->shift = shift;
    instr->comptype = 0;
    /* The dest register can be mapped normally to a temporary register */
    This->funcs->dstreg(This, instr, dst);
    /* Use the src passed as parameter by the specific instruction handler */
    instr->src[0] = *src0;

    /* The 2nd source register is the sampler register with the
     * destination's regnum
     */
    ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
    instr->src[1].type = BWRITERSPR_SAMPLER;
    instr->src[1].regnum = dst->regnum;
396
    instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
397 398 399 400 401
    instr->src[1].srcmod = BWRITERSPSM_NONE;
    instr->src[1].rel_reg = NULL;

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
402
        set_parse_status(&This->status, PARSE_ERR);
403 404 405 406 407 408 409 410 411 412 413 414
    }
}

static void asmparser_tex(struct asm_parser *This, DWORD mod, DWORD shift,
                          const struct shader_reg *dst) {
    struct shader_reg src;

    /* The first source register is the varying containing the coordinate */
    src = map_oldps_register(dst, TRUE);
    asmparser_texhelper(This, mod, shift, dst, &src);
}

415 416 417 418 419 420 421
static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
                              const struct shader_reg *dst,
                              const struct src_regs *srcs) {
    struct instruction *instr;

    if(!srcs || srcs->count != 1) {
        asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no);
422
        set_parse_status(&This->status, PARSE_ERR);
423 424 425 426 427 428
        return;
    }

    instr = alloc_instr(2);
    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
429
        set_parse_status(&This->status, PARSE_ERR);
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
        return;
    }

    /* This code is recording a texld instruction, not tex. However,
     * texld borrows the opcode of tex
     */
    instr->opcode = BWRITERSIO_TEX;
    instr->dstmod = mod;
    instr->shift = shift;
    instr->comptype = 0;

    This->funcs->dstreg(This, instr, dst);
    This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);

    /* The 2nd source register is the sampler register with the
     * destination's regnum
     */
    ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
    instr->src[1].type = BWRITERSPR_SAMPLER;
    instr->src[1].regnum = dst->regnum;
450
    instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
451 452 453 454 455
    instr->src[1].srcmod = BWRITERSPSM_NONE;
    instr->src[1].rel_reg = NULL;

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
456
        set_parse_status(&This->status, PARSE_ERR);
457 458 459
    }
}

460 461 462 463 464 465 466
static void asmparser_texreg2ar(struct asm_parser *This, DWORD mod, DWORD shift,
                                const struct shader_reg *dst,
                                const struct shader_reg *src0) {
    struct shader_reg src;

    src = map_oldps_register(src0, FALSE);
    /* Supply the correct swizzle */
467
    src.u.swizzle = BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X;
468 469 470 471 472 473 474 475 476 477
    asmparser_texhelper(This, mod, shift, dst, &src);
}

static void asmparser_texreg2gb(struct asm_parser *This, DWORD mod, DWORD shift,
                                const struct shader_reg *dst,
                                const struct shader_reg *src0) {
    struct shader_reg src;

    src = map_oldps_register(src0, FALSE);
    /* Supply the correct swizzle */
478
    src.u.swizzle = BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z;
479 480 481 482 483 484 485 486 487 488
    asmparser_texhelper(This, mod, shift, dst, &src);
}

static void asmparser_texreg2rgb(struct asm_parser *This, DWORD mod, DWORD shift,
                                 const struct shader_reg *dst,
                                 const struct shader_reg *src0) {
    struct shader_reg src;

    src = map_oldps_register(src0, FALSE);
    /* Supply the correct swizzle */
489
    src.u.swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z;
490 491 492 493 494 495 496 497 498 499
    asmparser_texhelper(This, mod, shift, dst, &src);
}

/* Complex pixel shader 1.3 instructions like texm3x3tex are tricky - the
 * bytecode writer works instruction by instruction, so we can't properly
 * convert these from/to equivalent ps_3_0 instructions. Then simply keep using
 * the ps_1_3 opcodes and just adapt the registers in the common fashion (i.e.
 * go through asmparser_instr).
 */

500 501 502 503
static void asmparser_instr(struct asm_parser *This, DWORD opcode, DWORD mod, DWORD shift,
        enum bwriter_comparison_type comp, const struct shader_reg *dst,
        const struct src_regs *srcs, int expectednsrcs)
{
504
    struct bwriter_shader *shader = This->shader;
505 506 507 508 509 510 511
    struct instruction *instr;
    unsigned int i;
    BOOL firstreg = TRUE;
    unsigned int src_count = srcs ? srcs->count : 0;

    if(!This->shader) return;

512
    TRACE_(parsed_shader)("%s%s%s%s ", debug_print_opcode(opcode),
513
                          debug_print_dstmod(mod),
514
                          debug_print_shift(shift),
515
                          debug_print_comp(comp));
516
    if(dst) {
517
        TRACE_(parsed_shader)("%s", debug_print_dstreg(dst));
518 519 520 521 522
        firstreg = FALSE;
    }
    for(i = 0; i < src_count; i++) {
        if(!firstreg) TRACE_(parsed_shader)(", ");
        else firstreg = FALSE;
523
        TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i]));
524 525 526
    }
    TRACE_(parsed_shader)("\n");

527
 /* Check for instructions with different syntaxes in different shader versions */
528 529 530
    switch(opcode) {
        case BWRITERSIO_SINCOS:
            /* The syntax changes between vs 2 and the other shader versions */
531 532
            if (This->shader->type == ST_VERTEX && This->shader->major_version == 2)
            {
533 534 535 536
                asmparser_sincos(This, mod, shift, dst, srcs);
                return;
            }
            /* Use the default handling */
537
            break;
538 539
        case BWRITERSIO_TEXCOORD:
            /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
540
            if (shader->type == ST_PIXEL && shader->major_version == 1 && shader->minor_version == 4)
541
                asmparser_texcrd(This, mod, shift, dst, srcs);
542 543
            else
                asmparser_texcoord(This, mod, shift, dst, srcs);
544 545 546 547
            return;
        case BWRITERSIO_TEX:
            /* this encodes both the tex PS 1.x instruction and the
               texld 1.4/2.0+ instruction */
548 549 550 551 552 553
            if (shader->type == ST_PIXEL && shader->major_version == 1)
            {
                if (shader->minor_version < 4)
                    asmparser_tex(This, mod, shift, dst);
                else
                    asmparser_texld14(This, mod, shift, dst, srcs);
554 555 556
                return;
            }
            /* else fallback to the standard behavior */
557 558 559
            break;
    }

560 561
    if(src_count != expectednsrcs) {
        asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
562
        set_parse_status(&This->status, PARSE_ERR);
563 564 565
        return;
    }

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
    /* Handle PS 1.x instructions, "regularizing" them */
    switch(opcode) {
        case BWRITERSIO_TEXKILL:
            asmparser_texkill(This, dst);
            return;
        case BWRITERSIO_TEXREG2AR:
            asmparser_texreg2ar(This, mod, shift, dst, &srcs->reg[0]);
            return;
        case BWRITERSIO_TEXREG2GB:
            asmparser_texreg2gb(This, mod, shift, dst, &srcs->reg[0]);
            return;
        case BWRITERSIO_TEXREG2RGB:
            asmparser_texreg2rgb(This, mod, shift, dst, &srcs->reg[0]);
            return;
    }

582 583 584
    instr = alloc_instr(src_count);
    if(!instr) {
        ERR("Error allocating memory for the instruction\n");
585
        set_parse_status(&This->status, PARSE_ERR);
586 587 588 589 590 591 592 593 594 595 596 597 598 599
        return;
    }

    instr->opcode = opcode;
    instr->dstmod = mod;
    instr->shift = shift;
    instr->comptype = comp;
    if(dst) This->funcs->dstreg(This, instr, dst);
    for(i = 0; i < src_count; i++) {
        This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
    }

    if(!add_instruction(This->shader, instr)) {
        ERR("Out of memory\n");
600
        set_parse_status(&This->status, PARSE_ERR);
601 602 603
    }
}

604 605 606 607 608 609 610 611 612 613 614 615
static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
    struct shader_reg ret;
    switch(reg->type) {
        case BWRITERSPR_RASTOUT:
            ret = *reg;
            ret.type = BWRITERSPR_OUTPUT;
            switch(reg->regnum) {
                case BWRITERSRO_POSITION:
                    ret.regnum = OPOS_REG;
                    break;
                case BWRITERSRO_FOG:
                    ret.regnum = OFOG_REG;
616
                    ret.u.writemask = OFOG_WRITEMASK;
617 618 619
                    break;
                case BWRITERSRO_POINT_SIZE:
                    ret.regnum = OPTS_REG;
620
                    ret.u.writemask = OPTS_WRITEMASK;
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
                    break;
                default:
                    FIXME("Unhandled RASTOUT register %u\n", reg->regnum);
                    return *reg;
            }
            return ret;

        case BWRITERSPR_TEXCRDOUT:
            ret = *reg;
            ret.type = BWRITERSPR_OUTPUT;
            switch(reg->regnum) {
                case 0: ret.regnum = OT0_REG; break;
                case 1: ret.regnum = OT1_REG; break;
                case 2: ret.regnum = OT2_REG; break;
                case 3: ret.regnum = OT3_REG; break;
                case 4: ret.regnum = OT4_REG; break;
                case 5: ret.regnum = OT5_REG; break;
                case 6: ret.regnum = OT6_REG; break;
                case 7: ret.regnum = OT7_REG; break;
                default:
                    FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum);
                    return *reg;
            }
            return ret;

        case BWRITERSPR_ATTROUT:
            ret = *reg;
            ret.type = BWRITERSPR_OUTPUT;
            switch(reg->regnum) {
                case 0: ret.regnum = OD0_REG; break;
                case 1: ret.regnum = OD1_REG; break;
                default:
                    FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum);
                    return *reg;
            }
            return ret;

        default: return *reg;
    }
}

662 663 664 665 666 667 668 669 670 671 672
/* Checks for unsupported source modifiers in VS (all versions) or
   PS 2.0 and newer */
static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
    if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG ||
       srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG ||
       srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 ||
       srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ ||
       srcmod == BWRITERSPSM_DW) {
        asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
                          This->line_no,
                          debug_print_srcmod(srcmod));
673
        set_parse_status(&This->status, PARSE_ERR);
674 675 676
    }
}

677 678 679 680 681
static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) {
    if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) {
        asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
                          This->line_no,
                          debug_print_srcmod(srcmod));
682
        set_parse_status(&This->status, PARSE_ERR);
683 684 685
    }
}

686 687
static void check_loop_swizzle(struct asm_parser *This,
                               const struct shader_reg *src) {
688
    if((src->type == BWRITERSPR_LOOP && src->u.swizzle != BWRITERVS_NOSWIZZLE) ||
689
       (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP &&
690
        src->rel_reg->u.swizzle != BWRITERVS_NOSWIZZLE)) {
691
        asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no);
692
        set_parse_status(&This->status, PARSE_ERR);
693 694 695 696 697 698 699
    }
}

static void check_shift_dstmod(struct asm_parser *This, DWORD shift) {
    if(shift != 0) {
        asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n",
                          This->line_no);
700
        set_parse_status(&This->status, PARSE_ERR);
701 702 703 704 705 706 707 708 709
    }
}

static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) {
    if(dstmod == BWRITERSPDM_PARTIALPRECISION ||
       dstmod == BWRITERSPDM_MSAMPCENTROID) {
        asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n",
                          This->line_no,
                          debug_print_dstmod(dstmod));
710
        set_parse_status(&This->status, PARSE_ERR);
711 712 713 714 715 716
    }
}

struct allowed_reg_type {
    DWORD type;
    DWORD count;
717
    BOOL reladdr;
718 719 720 721 722 723 724 725
};

static BOOL check_reg_type(const struct shader_reg *reg,
                           const struct allowed_reg_type *allowed) {
    unsigned int i = 0;

    while(allowed[i].type != ~0U) {
        if(reg->type == allowed[i].type) {
726 727 728 729 730 731 732
            if(reg->rel_reg) {
                if(allowed[i].reladdr)
                    return TRUE; /* The relative addressing register
                                    can have a negative value, we
                                    can't check the register index */
                return FALSE;
            }
733 734 735 736 737 738 739 740 741
            if(reg->regnum < allowed[i].count) return TRUE;
            return FALSE;
        }
        i++;
    }
    return FALSE;
}

/* Native assembler doesn't do separate checks for src and dst registers */
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
static const struct allowed_reg_type vs_1_reg_allowed[] = {
    { BWRITERSPR_TEMP,         12,  FALSE },
    { BWRITERSPR_INPUT,        16,  FALSE },
    { BWRITERSPR_CONST,       ~0U,   TRUE },
    { BWRITERSPR_ADDR,          1,  FALSE },
    { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */
    { BWRITERSPR_ATTROUT,       2,  FALSE },
    { BWRITERSPR_TEXCRDOUT,     8,  FALSE },
    { ~0U, 0 } /* End tag */
};

/* struct instruction *asmparser_srcreg
 *
 * Records a source register in the instruction and does shader version
 * specific checks and modifications on it
 *
 * Parameters:
 *  This: Shader parser instance
 *  instr: instruction to store the register in
 *  num: Number of source register
 *  src: Pointer to source the register structure. The caller can free
 *  it afterwards
 */
static void asmparser_srcreg_vs_1(struct asm_parser *This,
                                  struct instruction *instr, int num,
                                  const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, vs_1_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n",
                          This->line_no,
773
                          debug_print_srcreg(src));
774
        set_parse_status(&This->status, PARSE_ERR);
775 776 777 778
    }
    check_legacy_srcmod(This, src->srcmod);
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldvs_register(src);
779
    instr->src[num] = reg;
780 781
}

782
static const struct allowed_reg_type vs_2_reg_allowed[] = {
783 784 785 786 787 788 789 790 791 792 793 794
    { BWRITERSPR_TEMP,      12,  FALSE },
    { BWRITERSPR_INPUT,     16,  FALSE },
    { BWRITERSPR_CONST,    ~0U,   TRUE },
    { BWRITERSPR_ADDR,       1,  FALSE },
    { BWRITERSPR_CONSTBOOL, 16,  FALSE },
    { BWRITERSPR_CONSTINT,  16,  FALSE },
    { BWRITERSPR_LOOP,       1,  FALSE },
    { BWRITERSPR_LABEL,   2048,  FALSE },
    { BWRITERSPR_PREDICATE,  1,  FALSE },
    { BWRITERSPR_RASTOUT,    3,  FALSE }, /* oPos, oFog and oPts */
    { BWRITERSPR_ATTROUT,    2,  FALSE },
    { BWRITERSPR_TEXCRDOUT,  8,  FALSE },
795 796 797 798 799 800 801 802 803 804 805
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_vs_2(struct asm_parser *This,
                                  struct instruction *instr, int num,
                                  const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, vs_2_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n",
                          This->line_no,
806
                          debug_print_srcreg(src));
807
        set_parse_status(&This->status, PARSE_ERR);
808 809 810 811 812
    }
    check_loop_swizzle(This, src);
    check_legacy_srcmod(This, src->srcmod);
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldvs_register(src);
813
    instr->src[num] = reg;
814 815
}

816
static const struct allowed_reg_type vs_3_reg_allowed[] = {
817 818 819 820 821 822 823 824 825 826 827
    { BWRITERSPR_TEMP,         32,  FALSE },
    { BWRITERSPR_INPUT,        16,   TRUE },
    { BWRITERSPR_CONST,       ~0U,   TRUE },
    { BWRITERSPR_ADDR,          1,  FALSE },
    { BWRITERSPR_CONSTBOOL,    16,  FALSE },
    { BWRITERSPR_CONSTINT,     16,  FALSE },
    { BWRITERSPR_LOOP,          1,  FALSE },
    { BWRITERSPR_LABEL,      2048,  FALSE },
    { BWRITERSPR_PREDICATE,     1,  FALSE },
    { BWRITERSPR_SAMPLER,       4,  FALSE },
    { BWRITERSPR_OUTPUT,       12,   TRUE },
828 829 830
    { ~0U, 0 } /* End tag */
};

831 832 833
static void asmparser_srcreg_vs_3(struct asm_parser *This,
                                  struct instruction *instr, int num,
                                  const struct shader_reg *src) {
834 835 836
    if(!check_reg_type(src, vs_3_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n",
                          This->line_no,
837
                          debug_print_srcreg(src));
838
        set_parse_status(&This->status, PARSE_ERR);
839 840 841
    }
    check_loop_swizzle(This, src);
    check_legacy_srcmod(This, src->srcmod);
842
    instr->src[num] = *src;
843 844
}

845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
static const struct allowed_reg_type ps_1_0123_reg_allowed[] = {
    { BWRITERSPR_CONST,     8,  FALSE },
    { BWRITERSPR_TEMP,      2,  FALSE },
    { BWRITERSPR_TEXTURE,   4,  FALSE },
    { BWRITERSPR_INPUT,     2,  FALSE },
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_ps_1_0123(struct asm_parser *This,
                                       struct instruction *instr, int num,
                                       const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, ps_1_0123_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in <== PS 1.3\n",
                          This->line_no,
                          debug_print_srcreg(src));
862
        set_parse_status(&This->status, PARSE_ERR);
863 864 865
    }
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldps_register(src, FALSE);
866
    instr->src[num] = reg;
867 868
}

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
static const struct allowed_reg_type ps_1_4_reg_allowed[] = {
    { BWRITERSPR_CONST,     8,  FALSE },
    { BWRITERSPR_TEMP,      6,  FALSE },
    { BWRITERSPR_TEXTURE,   6,  FALSE },
    { BWRITERSPR_INPUT,     2,  FALSE },
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_ps_1_4(struct asm_parser *This,
                                    struct instruction *instr, int num,
                                    const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, ps_1_4_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\n",
                          This->line_no,
                          debug_print_srcreg(src));
886
        set_parse_status(&This->status, PARSE_ERR);
887 888 889
    }
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldps_register(src, TRUE);
890
    instr->src[num] = reg;
891 892
}

893
static const struct allowed_reg_type ps_2_0_reg_allowed[] = {
894 895 896 897 898 899 900 901 902
    { BWRITERSPR_INPUT,         2,  FALSE },
    { BWRITERSPR_TEMP,         32,  FALSE },
    { BWRITERSPR_CONST,        32,  FALSE },
    { BWRITERSPR_CONSTINT,     16,  FALSE },
    { BWRITERSPR_CONSTBOOL,    16,  FALSE },
    { BWRITERSPR_SAMPLER,      16,  FALSE },
    { BWRITERSPR_TEXTURE,       8,  FALSE },
    { BWRITERSPR_COLOROUT,      4,  FALSE },
    { BWRITERSPR_DEPTHOUT,      1,  FALSE },
903 904 905 906 907 908 909 910 911 912 913
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_ps_2(struct asm_parser *This,
                                  struct instruction *instr, int num,
                                  const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, ps_2_0_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n",
                          This->line_no,
914
                          debug_print_srcreg(src));
915
        set_parse_status(&This->status, PARSE_ERR);
916 917 918 919
    }
    check_legacy_srcmod(This, src->srcmod);
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldps_register(src, TRUE);
920
    instr->src[num] = reg;
921 922 923
}

static const struct allowed_reg_type ps_2_x_reg_allowed[] = {
924 925 926 927 928 929 930 931 932 933 934
    { BWRITERSPR_INPUT,         2,  FALSE },
    { BWRITERSPR_TEMP,         32,  FALSE },
    { BWRITERSPR_CONST,        32,  FALSE },
    { BWRITERSPR_CONSTINT,     16,  FALSE },
    { BWRITERSPR_CONSTBOOL,    16,  FALSE },
    { BWRITERSPR_PREDICATE,     1,  FALSE },
    { BWRITERSPR_SAMPLER,      16,  FALSE },
    { BWRITERSPR_TEXTURE,       8,  FALSE },
    { BWRITERSPR_LABEL,      2048,  FALSE },
    { BWRITERSPR_COLOROUT,      4,  FALSE },
    { BWRITERSPR_DEPTHOUT,      1,  FALSE },
935 936 937 938 939 940 941 942 943 944 945
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_ps_2_x(struct asm_parser *This,
                                    struct instruction *instr, int num,
                                    const struct shader_reg *src) {
    struct shader_reg reg;

    if(!check_reg_type(src, ps_2_x_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n",
                          This->line_no,
946
                          debug_print_srcreg(src));
947
        set_parse_status(&This->status, PARSE_ERR);
948 949 950 951
    }
    check_legacy_srcmod(This, src->srcmod);
    check_abs_srcmod(This, src->srcmod);
    reg = map_oldps_register(src, TRUE);
952
    instr->src[num] = reg;
953 954
}

955
static const struct allowed_reg_type ps_3_reg_allowed[] = {
956 957 958 959 960 961 962 963 964 965 966 967
    { BWRITERSPR_INPUT,        10,   TRUE },
    { BWRITERSPR_TEMP,         32,  FALSE },
    { BWRITERSPR_CONST,       224,  FALSE },
    { BWRITERSPR_CONSTINT,     16,  FALSE },
    { BWRITERSPR_CONSTBOOL,    16,  FALSE },
    { BWRITERSPR_PREDICATE,     1,  FALSE },
    { BWRITERSPR_SAMPLER,      16,  FALSE },
    { BWRITERSPR_MISCTYPE,      2,  FALSE }, /* vPos and vFace */
    { BWRITERSPR_LOOP,          1,  FALSE },
    { BWRITERSPR_LABEL,      2048,  FALSE },
    { BWRITERSPR_COLOROUT,      4,  FALSE },
    { BWRITERSPR_DEPTHOUT,      1,  FALSE },
968 969 970 971 972 973 974 975 976
    { ~0U, 0 } /* End tag */
};

static void asmparser_srcreg_ps_3(struct asm_parser *This,
                                  struct instruction *instr, int num,
                                  const struct shader_reg *src) {
    if(!check_reg_type(src, ps_3_reg_allowed)) {
        asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n",
                          This->line_no,
977
                          debug_print_srcreg(src));
978
        set_parse_status(&This->status, PARSE_ERR);
979 980 981
    }
    check_loop_swizzle(This, src);
    check_legacy_srcmod(This, src->srcmod);
982
    instr->src[num] = *src;
983 984
}

985 986 987 988 989 990 991 992
static void asmparser_dstreg_vs_1(struct asm_parser *This,
                                  struct instruction *instr,
                                  const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, vs_1_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n",
                          This->line_no,
993
                          debug_print_dstreg(dst));
994
        set_parse_status(&This->status, PARSE_ERR);
995 996 997 998
    }
    check_ps_dstmod(This, instr->dstmod);
    check_shift_dstmod(This, instr->shift);
    reg = map_oldvs_register(dst);
999
    instr->dst = reg;
1000 1001 1002
    instr->has_dst = TRUE;
}

1003 1004 1005 1006 1007 1008 1009 1010
static void asmparser_dstreg_vs_2(struct asm_parser *This,
                                  struct instruction *instr,
                                  const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, vs_2_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n",
                          This->line_no,
1011
                          debug_print_dstreg(dst));
1012
        set_parse_status(&This->status, PARSE_ERR);
1013 1014 1015 1016
    }
    check_ps_dstmod(This, instr->dstmod);
    check_shift_dstmod(This, instr->shift);
    reg = map_oldvs_register(dst);
1017
    instr->dst = reg;
1018 1019 1020
    instr->has_dst = TRUE;
}

1021 1022 1023
static void asmparser_dstreg_vs_3(struct asm_parser *This,
                                  struct instruction *instr,
                                  const struct shader_reg *dst) {
1024 1025 1026
    if(!check_reg_type(dst, vs_3_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n",
                          This->line_no,
1027
                          debug_print_dstreg(dst));
1028
        set_parse_status(&This->status, PARSE_ERR);
1029 1030 1031
    }
    check_ps_dstmod(This, instr->dstmod);
    check_shift_dstmod(This, instr->shift);
1032
    instr->dst = *dst;
1033 1034 1035
    instr->has_dst = TRUE;
}

1036 1037 1038 1039 1040 1041 1042 1043 1044
static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
                                       struct instruction *instr,
                                       const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, ps_1_0123_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
                          This->line_no,
                          debug_print_dstreg(dst));
1045
        set_parse_status(&This->status, PARSE_ERR);
1046 1047
    }
    reg = map_oldps_register(dst, FALSE);
1048
    instr->dst = reg;
1049 1050 1051
    instr->has_dst = TRUE;
}

1052 1053 1054 1055 1056 1057 1058 1059 1060
static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
                                    struct instruction *instr,
                                    const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, ps_1_4_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
                          This->line_no,
                          debug_print_dstreg(dst));
1061
        set_parse_status(&This->status, PARSE_ERR);
1062
    }
1063
    reg = map_oldps_register(dst, TRUE);
1064
    instr->dst = reg;
1065 1066 1067
    instr->has_dst = TRUE;
}

1068 1069 1070 1071 1072 1073 1074 1075
static void asmparser_dstreg_ps_2(struct asm_parser *This,
                                  struct instruction *instr,
                                  const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, ps_2_0_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n",
                          This->line_no,
1076
                          debug_print_dstreg(dst));
1077
        set_parse_status(&This->status, PARSE_ERR);
1078 1079 1080
    }
    check_shift_dstmod(This, instr->shift);
    reg = map_oldps_register(dst, TRUE);
1081
    instr->dst = reg;
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
    instr->has_dst = TRUE;
}

static void asmparser_dstreg_ps_2_x(struct asm_parser *This,
                                    struct instruction *instr,
                                    const struct shader_reg *dst) {
    struct shader_reg reg;

    if(!check_reg_type(dst, ps_2_x_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n",
                          This->line_no,
1093
                          debug_print_dstreg(dst));
1094
        set_parse_status(&This->status, PARSE_ERR);
1095 1096 1097
    }
    check_shift_dstmod(This, instr->shift);
    reg = map_oldps_register(dst, TRUE);
1098
    instr->dst = reg;
1099 1100 1101
    instr->has_dst = TRUE;
}

1102 1103 1104 1105 1106 1107
static void asmparser_dstreg_ps_3(struct asm_parser *This,
                                  struct instruction *instr,
                                  const struct shader_reg *dst) {
    if(!check_reg_type(dst, ps_3_reg_allowed)) {
        asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n",
                          This->line_no,
1108
                          debug_print_dstreg(dst));
1109
        set_parse_status(&This->status, PARSE_ERR);
1110 1111
    }
    check_shift_dstmod(This, instr->shift);
1112
    instr->dst = *dst;
1113 1114 1115
    instr->has_dst = TRUE;
}

1116 1117 1118 1119 1120 1121
static void asmparser_predicate_supported(struct asm_parser *This,
                                          const struct shader_reg *predicate) {
    /* this sets the predicate of the last instruction added to the shader */
    if(!This->shader) return;
    if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n");
    This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE;
1122
    This->shader->instr[This->shader->num_instrs - 1]->predicate = *predicate;
1123 1124
}

1125 1126 1127
static void asmparser_predicate_unsupported(struct asm_parser *This,
                                            const struct shader_reg *predicate) {
    asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
1128
    set_parse_status(&This->status, PARSE_ERR);
1129 1130
}

1131 1132 1133 1134 1135
static void asmparser_coissue_supported(struct asm_parser *This) {
    /* this sets the coissue flag of the last instruction added to the shader */
    if(!This->shader) return;
    if(This->shader->num_instrs == 0){
        asmparser_message(This, "Line %u: Coissue flag on the first shader instruction\n", This->line_no);
1136
        set_parse_status(&This->status, PARSE_ERR);
1137 1138 1139 1140
    }
    This->shader->instr[This->shader->num_instrs-1]->coissue = TRUE;
}

1141 1142
static void asmparser_coissue_unsupported(struct asm_parser *This) {
    asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
1143
    set_parse_status(&This->status, PARSE_ERR);
1144 1145
}

1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
static const struct asmparser_backend parser_vs_1 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_vs_1,
    asmparser_srcreg_vs_1,

    asmparser_predicate_unsupported,
    asmparser_coissue_unsupported,

1157
    asmparser_dcl_output_unsupported,
1158
    asmparser_dcl_input,
1159
    asmparser_dcl_sampler_unsupported,
1160 1161 1162 1163 1164 1165

    asmparser_end,

    asmparser_instr,
};

1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
static const struct asmparser_backend parser_vs_2 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_vs_2,
    asmparser_srcreg_vs_2,

    asmparser_predicate_supported,
    asmparser_coissue_unsupported,

1177
    asmparser_dcl_output_unsupported,
1178
    asmparser_dcl_input,
1179
    asmparser_dcl_sampler_unsupported,
1180 1181 1182 1183 1184 1185

    asmparser_end,

    asmparser_instr,
};

1186
static const struct asmparser_backend parser_vs_3 = {
1187
    asmparser_constF,
1188
    asmparser_constI,
1189
    asmparser_constB,
1190

1191 1192 1193
    asmparser_dstreg_vs_3,
    asmparser_srcreg_vs_3,

1194
    asmparser_predicate_supported,
1195 1196
    asmparser_coissue_unsupported,

1197
    asmparser_dcl_output,
1198
    asmparser_dcl_input,
1199
    asmparser_dcl_sampler,
1200

1201 1202 1203 1204 1205
    asmparser_end,

    asmparser_instr,
};

1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
static const struct asmparser_backend parser_ps_1_0123 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_ps_1_0123,
    asmparser_srcreg_ps_1_0123,

    asmparser_predicate_unsupported,
    asmparser_coissue_supported,

    asmparser_dcl_output_unsupported,
    asmparser_dcl_input_unsupported,
    asmparser_dcl_sampler_unsupported,

    asmparser_end,

    asmparser_instr,
};

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
static const struct asmparser_backend parser_ps_1_4 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_ps_1_4,
    asmparser_srcreg_ps_1_4,

    asmparser_predicate_unsupported,
    asmparser_coissue_supported,

    asmparser_dcl_output_unsupported,
    asmparser_dcl_input_unsupported,
    asmparser_dcl_sampler_unsupported,

    asmparser_end,

    asmparser_instr,
};

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
static const struct asmparser_backend parser_ps_2 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_ps_2,
    asmparser_srcreg_ps_2,

    asmparser_predicate_unsupported,
    asmparser_coissue_unsupported,

1257
    asmparser_dcl_output_unsupported,
1258
    asmparser_dcl_input_ps_2,
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
    asmparser_dcl_sampler,

    asmparser_end,

    asmparser_instr,
};

static const struct asmparser_backend parser_ps_2_x = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_ps_2_x,
    asmparser_srcreg_ps_2_x,

    asmparser_predicate_supported,
    asmparser_coissue_unsupported,

1277
    asmparser_dcl_output_unsupported,
1278
    asmparser_dcl_input_ps_2,
1279 1280 1281 1282 1283 1284 1285
    asmparser_dcl_sampler,

    asmparser_end,

    asmparser_instr,
};

1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
static const struct asmparser_backend parser_ps_3 = {
    asmparser_constF,
    asmparser_constI,
    asmparser_constB,

    asmparser_dstreg_ps_3,
    asmparser_srcreg_ps_3,

    asmparser_predicate_supported,
    asmparser_coissue_unsupported,

1297
    asmparser_dcl_output_unsupported,
1298 1299 1300 1301 1302 1303 1304 1305
    asmparser_dcl_input,
    asmparser_dcl_sampler,

    asmparser_end,

    asmparser_instr,
};

1306
static void gen_oldvs_output(struct bwriter_shader *shader) {
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
    record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, 0, TRUE, OFOG_REG, OFOG_WRITEMASK, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, 0, TRUE, OPTS_REG, OPTS_WRITEMASK, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1320 1321
}

1322 1323
static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
    switch(texcoords) {
1324
        case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1325
            /* fall through */
1326
        case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1327
            /* fall through */
1328
        case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1329
            /* fall through */
1330
        case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1331
            /* fall through */
1332
        case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1333
            /* fall through */
1334
        case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1335
            /* fall through */
1336
        case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1337
            /* fall through */
1338
        case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1339
    };
1340 1341
    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1342 1343
}

1344 1345 1346
void create_vs10_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("vs_1_0\n");

1347
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1348 1349
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1350
        set_parse_status(&ret->status, PARSE_ERR);
1351 1352 1353 1354
        return;
    }

    ret->shader->type = ST_VERTEX;
1355 1356
    ret->shader->major_version = 1;
    ret->shader->minor_version = 0;
1357 1358 1359 1360 1361 1362 1363
    ret->funcs = &parser_vs_1;
    gen_oldvs_output(ret->shader);
}

void create_vs11_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("vs_1_1\n");

1364
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1365 1366
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1367
        set_parse_status(&ret->status, PARSE_ERR);
1368 1369 1370 1371
        return;
    }

    ret->shader->type = ST_VERTEX;
1372 1373
    ret->shader->major_version = 1;
    ret->shader->minor_version = 1;
1374 1375 1376 1377
    ret->funcs = &parser_vs_1;
    gen_oldvs_output(ret->shader);
}

1378 1379 1380
void create_vs20_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("vs_2_0\n");

1381
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1382 1383
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1384
        set_parse_status(&ret->status, PARSE_ERR);
1385 1386 1387 1388
        return;
    }

    ret->shader->type = ST_VERTEX;
1389 1390
    ret->shader->major_version = 2;
    ret->shader->minor_version = 0;
1391 1392 1393 1394 1395 1396 1397
    ret->funcs = &parser_vs_2;
    gen_oldvs_output(ret->shader);
}

void create_vs2x_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("vs_2_x\n");

1398
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1399 1400
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1401
        set_parse_status(&ret->status, PARSE_ERR);
1402 1403 1404 1405
        return;
    }

    ret->shader->type = ST_VERTEX;
1406 1407
    ret->shader->major_version = 2;
    ret->shader->minor_version = 1;
1408 1409 1410 1411
    ret->funcs = &parser_vs_2;
    gen_oldvs_output(ret->shader);
}

1412 1413 1414
void create_vs30_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("vs_3_0\n");

1415
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1416 1417
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1418
        set_parse_status(&ret->status, PARSE_ERR);
1419 1420 1421 1422
        return;
    }

    ret->shader->type = ST_VERTEX;
1423 1424
    ret->shader->major_version = 3;
    ret->shader->minor_version = 0;
1425 1426
    ret->funcs = &parser_vs_3;
}
1427

1428 1429 1430
void create_ps10_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_1_0\n");

1431
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1432 1433
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1434
        set_parse_status(&ret->status, PARSE_ERR);
1435 1436 1437 1438
        return;
    }

    ret->shader->type = ST_PIXEL;
1439 1440
    ret->shader->major_version = 1;
    ret->shader->minor_version = 0;
1441 1442 1443 1444 1445 1446 1447
    ret->funcs = &parser_ps_1_0123;
    gen_oldps_input(ret->shader, 4);
}

void create_ps11_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_1_1\n");

1448
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1449 1450
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1451
        set_parse_status(&ret->status, PARSE_ERR);
1452 1453 1454 1455
        return;
    }

    ret->shader->type = ST_PIXEL;
1456 1457
    ret->shader->major_version = 1;
    ret->shader->minor_version = 1;
1458 1459 1460 1461 1462 1463 1464
    ret->funcs = &parser_ps_1_0123;
    gen_oldps_input(ret->shader, 4);
}

void create_ps12_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_1_2\n");

1465
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1466 1467
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1468
        set_parse_status(&ret->status, PARSE_ERR);
1469 1470 1471 1472
        return;
    }

    ret->shader->type = ST_PIXEL;
1473 1474
    ret->shader->major_version = 1;
    ret->shader->minor_version = 2;
1475 1476 1477 1478 1479 1480 1481
    ret->funcs = &parser_ps_1_0123;
    gen_oldps_input(ret->shader, 4);
}

void create_ps13_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_1_3\n");

1482
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1483 1484
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1485
        set_parse_status(&ret->status, PARSE_ERR);
1486 1487 1488 1489
        return;
    }

    ret->shader->type = ST_PIXEL;
1490 1491
    ret->shader->major_version = 1;
    ret->shader->minor_version = 3;
1492 1493 1494 1495
    ret->funcs = &parser_ps_1_0123;
    gen_oldps_input(ret->shader, 4);
}

1496 1497 1498
void create_ps14_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_1_4\n");

1499
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1500 1501
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1502
        set_parse_status(&ret->status, PARSE_ERR);
1503 1504 1505 1506
        return;
    }

    ret->shader->type = ST_PIXEL;
1507 1508
    ret->shader->major_version = 1;
    ret->shader->minor_version = 4;
1509 1510 1511 1512
    ret->funcs = &parser_ps_1_4;
    gen_oldps_input(ret->shader, 6);
}

1513 1514 1515
void create_ps20_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_2_0\n");

1516
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1517 1518
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1519
        set_parse_status(&ret->status, PARSE_ERR);
1520 1521 1522 1523
        return;
    }

    ret->shader->type = ST_PIXEL;
1524 1525
    ret->shader->major_version = 2;
    ret->shader->minor_version = 0;
1526 1527 1528 1529 1530 1531 1532
    ret->funcs = &parser_ps_2;
    gen_oldps_input(ret->shader, 8);
}

void create_ps2x_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_2_x\n");

1533
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1534 1535
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1536
        set_parse_status(&ret->status, PARSE_ERR);
1537 1538 1539 1540
        return;
    }

    ret->shader->type = ST_PIXEL;
1541 1542
    ret->shader->major_version = 2;
    ret->shader->minor_version = 1;
1543 1544 1545 1546
    ret->funcs = &parser_ps_2_x;
    gen_oldps_input(ret->shader, 8);
}

1547 1548 1549
void create_ps30_parser(struct asm_parser *ret) {
    TRACE_(parsed_shader)("ps_3_0\n");

1550
    ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1551 1552
    if(!ret->shader) {
        ERR("Failed to allocate memory for the shader\n");
1553
        set_parse_status(&ret->status, PARSE_ERR);
1554 1555 1556 1557
        return;
    }

    ret->shader->type = ST_PIXEL;
1558 1559
    ret->shader->major_version = 3;
    ret->shader->minor_version = 0;
1560 1561
    ret->funcs = &parser_ps_3;
}