1 /*
2  * Direct3D asm shader parser
3  *
4  * Copyright 2008 Stefan Dösinger
5  * Copyright 2009 Matteo Bruni
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 #include "wine/debug.h"
24 
25 #include "d3dcompiler_private.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
28 WINE_DECLARE_DEBUG_CHANNEL(parsed_shader);
29 
30 
31 /* How to map vs 1.0 and 2.0 varyings to 3.0 ones
32  * oTx is mapped to ox, which happens to be an
33  * identical mapping since BWRITERSPR_TEXCRDOUT == BWRITERSPR_OUTPUT
34  * oPos, oFog and point size are mapped to general output regs as well.
35  * the vs 1.x and 2.x parser functions add varying declarations
36  * to the shader, and the 1.x and 2.x output functions check those varyings
37  */
38 #define OT0_REG         0
39 #define OT1_REG         1
40 #define OT2_REG         2
41 #define OT3_REG         3
42 #define OT4_REG         4
43 #define OT5_REG         5
44 #define OT6_REG         6
45 #define OT7_REG         7
46 #define OPOS_REG        8
47 #define OFOG_REG        9
48 #define OFOG_WRITEMASK  BWRITERSP_WRITEMASK_0
49 #define OPTS_REG        9
50 #define OPTS_WRITEMASK  BWRITERSP_WRITEMASK_1
51 #define OD0_REG         10
52 #define OD1_REG         11
53 
54 /* Input color registers 0-1 are identically mapped */
55 #define C0_VARYING      0
56 #define C1_VARYING      1
57 #define T0_VARYING      2
58 #define T1_VARYING      3
59 #define T2_VARYING      4
60 #define T3_VARYING      5
61 #define T4_VARYING      6
62 #define T5_VARYING      7
63 #define T6_VARYING      8
64 #define T7_VARYING      9
65 
66 /****************************************************************
67  * Common(non-version specific) shader parser control code      *
68  ****************************************************************/
69 
70 static void asmparser_end(struct asm_parser *This) {
71     TRACE("Finalizing shader\n");
72 }
73 
74 static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) {
75     if(!This->shader) return;
76     TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf);
77     TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w);
78     if(!add_constF(This->shader, reg, x, y, z, w)) {
79         ERR("Out of memory\n");
80         set_parse_status(&This->status, PARSE_ERR);
81     }
82 }
83 
84 static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) {
85     if(!This->shader) return;
86     TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb);
87     TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false");
88     if(!add_constB(This->shader, reg, x)) {
89         ERR("Out of memory\n");
90         set_parse_status(&This->status, PARSE_ERR);
91     }
92 }
93 
94 static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) {
95     if(!This->shader) return;
96     TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci);
97     TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w);
98     if(!add_constI(This->shader, reg, x, y, z, w)) {
99         ERR("Out of memory\n");
100         set_parse_status(&This->status, PARSE_ERR);
101     }
102 }
103 
104 static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num,
105                                  const struct shader_reg *reg) {
106     if(!This->shader) return;
107     if(This->shader->type == ST_PIXEL) {
108         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 static void asmparser_dcl_output_unsupported(struct asm_parser *This, DWORD usage, DWORD num,
118                                              const struct shader_reg *reg) {
119     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     struct instruction instr;
126 
127     if(!This->shader) return;
128     if(mod != 0 &&
129        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
130         (mod != BWRITERSPDM_MSAMPCENTROID &&
131          mod != BWRITERSPDM_PARTIALPRECISION))) {
132         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
133         set_parse_status(&This->status, PARSE_ERR);
134         return;
135     }
136 
137     /* Check register type and modifiers */
138     instr.dstmod = mod;
139     instr.shift = 0;
140     This->funcs->dstreg(This, &instr, reg);
141 
142     if(!record_declaration(This->shader, usage, num, mod, FALSE, reg->regnum, reg->u.writemask, FALSE)) {
143         ERR("Out of memory\n");
144         set_parse_status(&This->status, PARSE_ERR);
145     }
146 }
147 
148 static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD num,
149                                      DWORD mod, const struct shader_reg *reg) {
150     struct instruction instr;
151 
152     if(!This->shader) return;
153     instr.dstmod = mod;
154     instr.shift = 0;
155     This->funcs->dstreg(This, &instr, reg);
156     if(!record_declaration(This->shader, usage, num, mod, FALSE, instr.dst.regnum, instr.dst.u.writemask, FALSE)) {
157         ERR("Out of memory\n");
158         set_parse_status(&This->status, PARSE_ERR);
159     }
160 }
161 
162 static void asmparser_dcl_input_unsupported(struct asm_parser *This,
163         DWORD usage, DWORD num, DWORD mod, const struct shader_reg *reg)
164 {
165     asmparser_message(This, "Line %u: Input declaration unsupported in this shader version\n", This->line_no);
166     set_parse_status(&This->status, PARSE_ERR);
167 }
168 
169 static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype,
170                                   DWORD mod, DWORD regnum,
171                                   unsigned int line_no) {
172     if(!This->shader) return;
173     if(mod != 0 &&
174        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
175         (mod != BWRITERSPDM_MSAMPCENTROID &&
176          mod != BWRITERSPDM_PARTIALPRECISION))) {
177         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
178         set_parse_status(&This->status, PARSE_ERR);
179         return;
180     }
181     if(!record_sampler(This->shader, samptype, mod, regnum)) {
182         ERR("Out of memory\n");
183         set_parse_status(&This->status, PARSE_ERR);
184     }
185 }
186 
187 static void asmparser_dcl_sampler_unsupported(struct asm_parser *This,
188         DWORD samptype, DWORD mod, DWORD regnum, unsigned int line_no)
189 {
190     asmparser_message(This, "Line %u: Sampler declaration unsupported in this shader version\n", This->line_no);
191     set_parse_status(&This->status, PARSE_ERR);
192 }
193 
194 static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
195                              const struct shader_reg *dst,
196                              const struct src_regs *srcs) {
197     struct instruction *instr;
198 
199     if(!srcs || srcs->count != 3) {
200         asmparser_message(This, "Line %u: sincos (vs 2) has an incorrect number of source registers\n", This->line_no);
201         set_parse_status(&This->status, PARSE_ERR);
202         return;
203     }
204 
205     instr = alloc_instr(3);
206     if(!instr) {
207         ERR("Error allocating memory for the instruction\n");
208         set_parse_status(&This->status, PARSE_ERR);
209         return;
210     }
211 
212     instr->opcode = BWRITERSIO_SINCOS;
213     instr->dstmod = mod;
214     instr->shift = shift;
215     instr->comptype = 0;
216 
217     This->funcs->dstreg(This, instr, dst);
218     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
219     This->funcs->srcreg(This, instr, 1, &srcs->reg[1]);
220     This->funcs->srcreg(This, instr, 2, &srcs->reg[2]);
221 
222     if(!add_instruction(This->shader, instr)) {
223         ERR("Out of memory\n");
224         set_parse_status(&This->status, PARSE_ERR);
225     }
226 }
227 
228 static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
229     struct shader_reg ret;
230     switch(reg->type) {
231         case BWRITERSPR_TEXTURE:
232             if(tex_varying) {
233                 ret = *reg;
234                 ret.type = BWRITERSPR_INPUT;
235                 switch(reg->regnum) {
236                     case 0:     ret.regnum = T0_VARYING; break;
237                     case 1:     ret.regnum = T1_VARYING; break;
238                     case 2:     ret.regnum = T2_VARYING; break;
239                     case 3:     ret.regnum = T3_VARYING; break;
240                     case 4:     ret.regnum = T4_VARYING; break;
241                     case 5:     ret.regnum = T5_VARYING; break;
242                     case 6:     ret.regnum = T6_VARYING; break;
243                     case 7:     ret.regnum = T7_VARYING; break;
244                     default:
245                         FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
246                         return *reg;
247                 }
248                 return ret;
249             } else {
250                 ret = *reg;
251                 ret.type = BWRITERSPR_TEMP;
252                 switch(reg->regnum) {
253                     case 0:     ret.regnum = T0_REG; break;
254                     case 1:     ret.regnum = T1_REG; break;
255                     case 2:     ret.regnum = T2_REG; break;
256                     case 3:     ret.regnum = T3_REG; break;
257                     default:
258                         FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
259                         return *reg;
260                 }
261                 return ret;
262             }
263 
264         /* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
265            to 3.0 ones */
266 
267         default: return *reg;
268     }
269 }
270 
271 static void asmparser_texcoord(struct asm_parser *This, DWORD mod, DWORD shift,
272                                const struct shader_reg *dst,
273                                const struct src_regs *srcs) {
274     struct instruction *instr;
275 
276     if(srcs) {
277         asmparser_message(This, "Line %u: Source registers in texcoord instruction\n", This->line_no);
278         set_parse_status(&This->status, PARSE_ERR);
279         return;
280     }
281 
282     instr = alloc_instr(1);
283     if(!instr) {
284         ERR("Error allocating memory for the instruction\n");
285         set_parse_status(&This->status, PARSE_ERR);
286         return;
287     }
288 
289     /* texcoord copies the texture coord data into a temporary register-like
290      * readable form. In newer shader models this equals a MOV from v0 to r0,
291      * record it as this.
292      */
293     instr->opcode = BWRITERSIO_MOV;
294     instr->dstmod = mod | BWRITERSPDM_SATURATE; /* texcoord clamps to [0;1] */
295     instr->shift = shift;
296     instr->comptype = 0;
297 
298     This->funcs->dstreg(This, instr, dst);
299     /* The src reg needs special care */
300     instr->src[0] = map_oldps_register(dst, TRUE);
301 
302     if(!add_instruction(This->shader, instr)) {
303         ERR("Out of memory\n");
304         set_parse_status(&This->status, PARSE_ERR);
305     }
306 }
307 
308 static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
309                              const struct shader_reg *dst,
310                              const struct src_regs *srcs) {
311     struct instruction *instr;
312 
313     if(!srcs || srcs->count != 1) {
314         asmparser_message(This, "Line %u: Wrong number of source registers in texcrd instruction\n", This->line_no);
315         set_parse_status(&This->status, PARSE_ERR);
316         return;
317     }
318 
319     instr = alloc_instr(1);
320     if(!instr) {
321         ERR("Error allocating memory for the instruction\n");
322         set_parse_status(&This->status, PARSE_ERR);
323         return;
324     }
325 
326     /* The job of texcrd is done by mov in later shader versions */
327     instr->opcode = BWRITERSIO_MOV;
328     instr->dstmod = mod;
329     instr->shift = shift;
330     instr->comptype = 0;
331 
332     This->funcs->dstreg(This, instr, dst);
333     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
334 
335     if(!add_instruction(This->shader, instr)) {
336         ERR("Out of memory\n");
337         set_parse_status(&This->status, PARSE_ERR);
338     }
339 }
340 
341 static void asmparser_texkill(struct asm_parser *This,
342                               const struct shader_reg *dst) {
343     struct instruction *instr = alloc_instr(0);
344 
345     if(!instr) {
346         ERR("Error allocating memory for the instruction\n");
347         set_parse_status(&This->status, PARSE_ERR);
348         return;
349     }
350 
351     instr->opcode = BWRITERSIO_TEXKILL;
352     instr->dstmod = 0;
353     instr->shift = 0;
354     instr->comptype = 0;
355 
356     /* Do not run the dst register through the normal
357      * register conversion. If used with ps_1_0 to ps_1_3
358      * the texture coordinate from that register is used,
359      * not the temporary register value. In ps_1_4 and
360      * ps_2_0 t0 is always a varying and temporaries can
361      * be used with texkill.
362      */
363     instr->dst = map_oldps_register(dst, TRUE);
364     instr->has_dst = TRUE;
365 
366     if(!add_instruction(This->shader, instr)) {
367         ERR("Out of memory\n");
368         set_parse_status(&This->status, PARSE_ERR);
369     }
370 }
371 
372 static void asmparser_texhelper(struct asm_parser *This, DWORD mod, DWORD shift,
373                                 const struct shader_reg *dst,
374                                 const struct shader_reg *src0) {
375     struct instruction *instr = alloc_instr(2);
376 
377     if(!instr) {
378         ERR("Error allocating memory for the instruction\n");
379         set_parse_status(&This->status, PARSE_ERR);
380         return;
381     }
382 
383     instr->opcode = BWRITERSIO_TEX;
384     instr->dstmod = mod;
385     instr->shift = shift;
386     instr->comptype = 0;
387     /* The dest register can be mapped normally to a temporary register */
388     This->funcs->dstreg(This, instr, dst);
389     /* Use the src passed as parameter by the specific instruction handler */
390     instr->src[0] = *src0;
391 
392     /* The 2nd source register is the sampler register with the
393      * destination's regnum
394      */
395     ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
396     instr->src[1].type = BWRITERSPR_SAMPLER;
397     instr->src[1].regnum = dst->regnum;
398     instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
399     instr->src[1].srcmod = BWRITERSPSM_NONE;
400     instr->src[1].rel_reg = NULL;
401 
402     if(!add_instruction(This->shader, instr)) {
403         ERR("Out of memory\n");
404         set_parse_status(&This->status, PARSE_ERR);
405     }
406 }
407 
408 static void asmparser_tex(struct asm_parser *This, DWORD mod, DWORD shift,
409                           const struct shader_reg *dst) {
410     struct shader_reg src;
411 
412     /* The first source register is the varying containing the coordinate */
413     src = map_oldps_register(dst, TRUE);
414     asmparser_texhelper(This, mod, shift, dst, &src);
415 }
416 
417 static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
418                               const struct shader_reg *dst,
419                               const struct src_regs *srcs) {
420     struct instruction *instr;
421 
422     if(!srcs || srcs->count != 1) {
423         asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no);
424         set_parse_status(&This->status, PARSE_ERR);
425         return;
426     }
427 
428     instr = alloc_instr(2);
429     if(!instr) {
430         ERR("Error allocating memory for the instruction\n");
431         set_parse_status(&This->status, PARSE_ERR);
432         return;
433     }
434 
435     /* This code is recording a texld instruction, not tex. However,
436      * texld borrows the opcode of tex
437      */
438     instr->opcode = BWRITERSIO_TEX;
439     instr->dstmod = mod;
440     instr->shift = shift;
441     instr->comptype = 0;
442 
443     This->funcs->dstreg(This, instr, dst);
444     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
445 
446     /* The 2nd source register is the sampler register with the
447      * destination's regnum
448      */
449     ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
450     instr->src[1].type = BWRITERSPR_SAMPLER;
451     instr->src[1].regnum = dst->regnum;
452     instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
453     instr->src[1].srcmod = BWRITERSPSM_NONE;
454     instr->src[1].rel_reg = NULL;
455 
456     if(!add_instruction(This->shader, instr)) {
457         ERR("Out of memory\n");
458         set_parse_status(&This->status, PARSE_ERR);
459     }
460 }
461 
462 static void asmparser_texreg2ar(struct asm_parser *This, DWORD mod, DWORD shift,
463                                 const struct shader_reg *dst,
464                                 const struct shader_reg *src0) {
465     struct shader_reg src;
466 
467     src = map_oldps_register(src0, FALSE);
468     /* Supply the correct swizzle */
469     src.u.swizzle = BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X;
470     asmparser_texhelper(This, mod, shift, dst, &src);
471 }
472 
473 static void asmparser_texreg2gb(struct asm_parser *This, DWORD mod, DWORD shift,
474                                 const struct shader_reg *dst,
475                                 const struct shader_reg *src0) {
476     struct shader_reg src;
477 
478     src = map_oldps_register(src0, FALSE);
479     /* Supply the correct swizzle */
480     src.u.swizzle = BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z;
481     asmparser_texhelper(This, mod, shift, dst, &src);
482 }
483 
484 static void asmparser_texreg2rgb(struct asm_parser *This, DWORD mod, DWORD shift,
485                                  const struct shader_reg *dst,
486                                  const struct shader_reg *src0) {
487     struct shader_reg src;
488 
489     src = map_oldps_register(src0, FALSE);
490     /* Supply the correct swizzle */
491     src.u.swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z;
492     asmparser_texhelper(This, mod, shift, dst, &src);
493 }
494 
495 /* Complex pixel shader 1.3 instructions like texm3x3tex are tricky - the
496  * bytecode writer works instruction by instruction, so we can't properly
497  * convert these from/to equivalent ps_3_0 instructions. Then simply keep using
498  * the ps_1_3 opcodes and just adapt the registers in the common fashion (i.e.
499  * go through asmparser_instr).
500  */
501 
502 static void asmparser_instr(struct asm_parser *This, DWORD opcode, DWORD mod, DWORD shift,
503         enum bwriter_comparison_type comp, const struct shader_reg *dst,
504         const struct src_regs *srcs, int expectednsrcs)
505 {
506     struct instruction *instr;
507     unsigned int i;
508     BOOL firstreg = TRUE;
509     unsigned int src_count = srcs ? srcs->count : 0;
510 
511     if(!This->shader) return;
512 
513     TRACE_(parsed_shader)("%s%s%s%s ", debug_print_opcode(opcode),
514                           debug_print_dstmod(mod),
515                           debug_print_shift(shift),
516                           debug_print_comp(comp));
517     if(dst) {
518         TRACE_(parsed_shader)("%s", debug_print_dstreg(dst));
519         firstreg = FALSE;
520     }
521     for(i = 0; i < src_count; i++) {
522         if(!firstreg) TRACE_(parsed_shader)(", ");
523         else firstreg = FALSE;
524         TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i]));
525     }
526     TRACE_(parsed_shader)("\n");
527 
528  /* Check for instructions with different syntaxes in different shader versions */
529     switch(opcode) {
530         case BWRITERSIO_SINCOS:
531             /* The syntax changes between vs 2 and the other shader versions */
532             if(This->shader->version == BWRITERVS_VERSION(2, 0) ||
533                This->shader->version == BWRITERVS_VERSION(2, 1)) {
534                 asmparser_sincos(This, mod, shift, dst, srcs);
535                 return;
536             }
537             /* Use the default handling */
538             break;
539         case BWRITERSIO_TEXCOORD:
540             /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
541             if(This->shader->version == BWRITERPS_VERSION(1, 4))
542                 asmparser_texcrd(This, mod, shift, dst, srcs);
543             else asmparser_texcoord(This, mod, shift, dst, srcs);
544             return;
545         case BWRITERSIO_TEX:
546             /* this encodes both the tex PS 1.x instruction and the
547                texld 1.4/2.0+ instruction */
548             if(This->shader->version == BWRITERPS_VERSION(1, 0) ||
549                This->shader->version == BWRITERPS_VERSION(1, 1) ||
550                This->shader->version == BWRITERPS_VERSION(1, 2) ||
551                This->shader->version == BWRITERPS_VERSION(1, 3)) {
552                 asmparser_tex(This, mod, shift, dst);
553                 return;
554             }
555             else if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
556                 asmparser_texld14(This, mod, shift, dst, srcs);
557                 return;
558             }
559             /* else fallback to the standard behavior */
560             break;
561     }
562 
563     if(src_count != expectednsrcs) {
564         asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
565         set_parse_status(&This->status, PARSE_ERR);
566         return;
567     }
568 
569     /* Handle PS 1.x instructions, "regularizing" them */
570     switch(opcode) {
571         case BWRITERSIO_TEXKILL:
572             asmparser_texkill(This, dst);
573             return;
574         case BWRITERSIO_TEXREG2AR:
575             asmparser_texreg2ar(This, mod, shift, dst, &srcs->reg[0]);
576             return;
577         case BWRITERSIO_TEXREG2GB:
578             asmparser_texreg2gb(This, mod, shift, dst, &srcs->reg[0]);
579             return;
580         case BWRITERSIO_TEXREG2RGB:
581             asmparser_texreg2rgb(This, mod, shift, dst, &srcs->reg[0]);
582             return;
583     }
584 
585     instr = alloc_instr(src_count);
586     if(!instr) {
587         ERR("Error allocating memory for the instruction\n");
588         set_parse_status(&This->status, PARSE_ERR);
589         return;
590     }
591 
592     instr->opcode = opcode;
593     instr->dstmod = mod;
594     instr->shift = shift;
595     instr->comptype = comp;
596     if(dst) This->funcs->dstreg(This, instr, dst);
597     for(i = 0; i < src_count; i++) {
598         This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
599     }
600 
601     if(!add_instruction(This->shader, instr)) {
602         ERR("Out of memory\n");
603         set_parse_status(&This->status, PARSE_ERR);
604     }
605 }
606 
607 static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
608     struct shader_reg ret;
609     switch(reg->type) {
610         case BWRITERSPR_RASTOUT:
611             ret = *reg;
612             ret.type = BWRITERSPR_OUTPUT;
613             switch(reg->regnum) {
614                 case BWRITERSRO_POSITION:
615                     ret.regnum = OPOS_REG;
616                     break;
617                 case BWRITERSRO_FOG:
618                     ret.regnum = OFOG_REG;
619                     ret.u.writemask = OFOG_WRITEMASK;
620                     break;
621                 case BWRITERSRO_POINT_SIZE:
622                     ret.regnum = OPTS_REG;
623                     ret.u.writemask = OPTS_WRITEMASK;
624                     break;
625                 default:
626                     FIXME("Unhandled RASTOUT register %u\n", reg->regnum);
627                     return *reg;
628             }
629             return ret;
630 
631         case BWRITERSPR_TEXCRDOUT:
632             ret = *reg;
633             ret.type = BWRITERSPR_OUTPUT;
634             switch(reg->regnum) {
635                 case 0: ret.regnum = OT0_REG; break;
636                 case 1: ret.regnum = OT1_REG; break;
637                 case 2: ret.regnum = OT2_REG; break;
638                 case 3: ret.regnum = OT3_REG; break;
639                 case 4: ret.regnum = OT4_REG; break;
640                 case 5: ret.regnum = OT5_REG; break;
641                 case 6: ret.regnum = OT6_REG; break;
642                 case 7: ret.regnum = OT7_REG; break;
643                 default:
644                     FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum);
645                     return *reg;
646             }
647             return ret;
648 
649         case BWRITERSPR_ATTROUT:
650             ret = *reg;
651             ret.type = BWRITERSPR_OUTPUT;
652             switch(reg->regnum) {
653                 case 0: ret.regnum = OD0_REG; break;
654                 case 1: ret.regnum = OD1_REG; break;
655                 default:
656                     FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum);
657                     return *reg;
658             }
659             return ret;
660 
661         default: return *reg;
662     }
663 }
664 
665 /* Checks for unsupported source modifiers in VS (all versions) or
666    PS 2.0 and newer */
667 static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
668     if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG ||
669        srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG ||
670        srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 ||
671        srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ ||
672        srcmod == BWRITERSPSM_DW) {
673         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
674                           This->line_no,
675                           debug_print_srcmod(srcmod));
676         set_parse_status(&This->status, PARSE_ERR);
677     }
678 }
679 
680 static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) {
681     if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) {
682         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
683                           This->line_no,
684                           debug_print_srcmod(srcmod));
685         set_parse_status(&This->status, PARSE_ERR);
686     }
687 }
688 
689 static void check_loop_swizzle(struct asm_parser *This,
690                                const struct shader_reg *src) {
691     if((src->type == BWRITERSPR_LOOP && src->u.swizzle != BWRITERVS_NOSWIZZLE) ||
692        (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP &&
693         src->rel_reg->u.swizzle != BWRITERVS_NOSWIZZLE)) {
694         asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no);
695         set_parse_status(&This->status, PARSE_ERR);
696     }
697 }
698 
699 static void check_shift_dstmod(struct asm_parser *This, DWORD shift) {
700     if(shift != 0) {
701         asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n",
702                           This->line_no);
703         set_parse_status(&This->status, PARSE_ERR);
704     }
705 }
706 
707 static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) {
708     if(dstmod == BWRITERSPDM_PARTIALPRECISION ||
709        dstmod == BWRITERSPDM_MSAMPCENTROID) {
710         asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n",
711                           This->line_no,
712                           debug_print_dstmod(dstmod));
713         set_parse_status(&This->status, PARSE_ERR);
714     }
715 }
716 
717 struct allowed_reg_type {
718     DWORD type;
719     DWORD count;
720     BOOL reladdr;
721 };
722 
723 static BOOL check_reg_type(const struct shader_reg *reg,
724                            const struct allowed_reg_type *allowed) {
725     unsigned int i = 0;
726 
727     while(allowed[i].type != ~0U) {
728         if(reg->type == allowed[i].type) {
729             if(reg->rel_reg) {
730                 if(allowed[i].reladdr)
731                     return TRUE; /* The relative addressing register
732                                     can have a negative value, we
733                                     can't check the register index */
734                 return FALSE;
735             }
736             if(reg->regnum < allowed[i].count) return TRUE;
737             return FALSE;
738         }
739         i++;
740     }
741     return FALSE;
742 }
743 
744 /* Native assembler doesn't do separate checks for src and dst registers */
745 static const struct allowed_reg_type vs_1_reg_allowed[] = {
746     { BWRITERSPR_TEMP,         12,  FALSE },
747     { BWRITERSPR_INPUT,        16,  FALSE },
748     { BWRITERSPR_CONST,       ~0U,   TRUE },
749     { BWRITERSPR_ADDR,          1,  FALSE },
750     { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */
751     { BWRITERSPR_ATTROUT,       2,  FALSE },
752     { BWRITERSPR_TEXCRDOUT,     8,  FALSE },
753     { ~0U, 0 } /* End tag */
754 };
755 
756 /* struct instruction *asmparser_srcreg
757  *
758  * Records a source register in the instruction and does shader version
759  * specific checks and modifications on it
760  *
761  * Parameters:
762  *  This: Shader parser instance
763  *  instr: instruction to store the register in
764  *  num: Number of source register
765  *  src: Pointer to source the register structure. The caller can free
766  *  it afterwards
767  */
768 static void asmparser_srcreg_vs_1(struct asm_parser *This,
769                                   struct instruction *instr, int num,
770                                   const struct shader_reg *src) {
771     struct shader_reg reg;
772 
773     if(!check_reg_type(src, vs_1_reg_allowed)) {
774         asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n",
775                           This->line_no,
776                           debug_print_srcreg(src));
777         set_parse_status(&This->status, PARSE_ERR);
778     }
779     check_legacy_srcmod(This, src->srcmod);
780     check_abs_srcmod(This, src->srcmod);
781     reg = map_oldvs_register(src);
782     instr->src[num] = reg;
783 }
784 
785 static const struct allowed_reg_type vs_2_reg_allowed[] = {
786     { BWRITERSPR_TEMP,      12,  FALSE },
787     { BWRITERSPR_INPUT,     16,  FALSE },
788     { BWRITERSPR_CONST,    ~0U,   TRUE },
789     { BWRITERSPR_ADDR,       1,  FALSE },
790     { BWRITERSPR_CONSTBOOL, 16,  FALSE },
791     { BWRITERSPR_CONSTINT,  16,  FALSE },
792     { BWRITERSPR_LOOP,       1,  FALSE },
793     { BWRITERSPR_LABEL,   2048,  FALSE },
794     { BWRITERSPR_PREDICATE,  1,  FALSE },
795     { BWRITERSPR_RASTOUT,    3,  FALSE }, /* oPos, oFog and oPts */
796     { BWRITERSPR_ATTROUT,    2,  FALSE },
797     { BWRITERSPR_TEXCRDOUT,  8,  FALSE },
798     { ~0U, 0 } /* End tag */
799 };
800 
801 static void asmparser_srcreg_vs_2(struct asm_parser *This,
802                                   struct instruction *instr, int num,
803                                   const struct shader_reg *src) {
804     struct shader_reg reg;
805 
806     if(!check_reg_type(src, vs_2_reg_allowed)) {
807         asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n",
808                           This->line_no,
809                           debug_print_srcreg(src));
810         set_parse_status(&This->status, PARSE_ERR);
811     }
812     check_loop_swizzle(This, src);
813     check_legacy_srcmod(This, src->srcmod);
814     check_abs_srcmod(This, src->srcmod);
815     reg = map_oldvs_register(src);
816     instr->src[num] = reg;
817 }
818 
819 static const struct allowed_reg_type vs_3_reg_allowed[] = {
820     { BWRITERSPR_TEMP,         32,  FALSE },
821     { BWRITERSPR_INPUT,        16,   TRUE },
822     { BWRITERSPR_CONST,       ~0U,   TRUE },
823     { BWRITERSPR_ADDR,          1,  FALSE },
824     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
825     { BWRITERSPR_CONSTINT,     16,  FALSE },
826     { BWRITERSPR_LOOP,          1,  FALSE },
827     { BWRITERSPR_LABEL,      2048,  FALSE },
828     { BWRITERSPR_PREDICATE,     1,  FALSE },
829     { BWRITERSPR_SAMPLER,       4,  FALSE },
830     { BWRITERSPR_OUTPUT,       12,   TRUE },
831     { ~0U, 0 } /* End tag */
832 };
833 
834 static void asmparser_srcreg_vs_3(struct asm_parser *This,
835                                   struct instruction *instr, int num,
836                                   const struct shader_reg *src) {
837     if(!check_reg_type(src, vs_3_reg_allowed)) {
838         asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n",
839                           This->line_no,
840                           debug_print_srcreg(src));
841         set_parse_status(&This->status, PARSE_ERR);
842     }
843     check_loop_swizzle(This, src);
844     check_legacy_srcmod(This, src->srcmod);
845     instr->src[num] = *src;
846 }
847 
848 static const struct allowed_reg_type ps_1_0123_reg_allowed[] = {
849     { BWRITERSPR_CONST,     8,  FALSE },
850     { BWRITERSPR_TEMP,      2,  FALSE },
851     { BWRITERSPR_TEXTURE,   4,  FALSE },
852     { BWRITERSPR_INPUT,     2,  FALSE },
853     { ~0U, 0 } /* End tag */
854 };
855 
856 static void asmparser_srcreg_ps_1_0123(struct asm_parser *This,
857                                        struct instruction *instr, int num,
858                                        const struct shader_reg *src) {
859     struct shader_reg reg;
860 
861     if(!check_reg_type(src, ps_1_0123_reg_allowed)) {
862         asmparser_message(This, "Line %u: Source register %s not supported in <== PS 1.3\n",
863                           This->line_no,
864                           debug_print_srcreg(src));
865         set_parse_status(&This->status, PARSE_ERR);
866     }
867     check_abs_srcmod(This, src->srcmod);
868     reg = map_oldps_register(src, FALSE);
869     instr->src[num] = reg;
870 }
871 
872 static const struct allowed_reg_type ps_1_4_reg_allowed[] = {
873     { BWRITERSPR_CONST,     8,  FALSE },
874     { BWRITERSPR_TEMP,      6,  FALSE },
875     { BWRITERSPR_TEXTURE,   6,  FALSE },
876     { BWRITERSPR_INPUT,     2,  FALSE },
877     { ~0U, 0 } /* End tag */
878 };
879 
880 static void asmparser_srcreg_ps_1_4(struct asm_parser *This,
881                                     struct instruction *instr, int num,
882                                     const struct shader_reg *src) {
883     struct shader_reg reg;
884 
885     if(!check_reg_type(src, ps_1_4_reg_allowed)) {
886         asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\n",
887                           This->line_no,
888                           debug_print_srcreg(src));
889         set_parse_status(&This->status, PARSE_ERR);
890     }
891     check_abs_srcmod(This, src->srcmod);
892     reg = map_oldps_register(src, TRUE);
893     instr->src[num] = reg;
894 }
895 
896 static const struct allowed_reg_type ps_2_0_reg_allowed[] = {
897     { BWRITERSPR_INPUT,         2,  FALSE },
898     { BWRITERSPR_TEMP,         32,  FALSE },
899     { BWRITERSPR_CONST,        32,  FALSE },
900     { BWRITERSPR_CONSTINT,     16,  FALSE },
901     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
902     { BWRITERSPR_SAMPLER,      16,  FALSE },
903     { BWRITERSPR_TEXTURE,       8,  FALSE },
904     { BWRITERSPR_COLOROUT,      4,  FALSE },
905     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
906     { ~0U, 0 } /* End tag */
907 };
908 
909 static void asmparser_srcreg_ps_2(struct asm_parser *This,
910                                   struct instruction *instr, int num,
911                                   const struct shader_reg *src) {
912     struct shader_reg reg;
913 
914     if(!check_reg_type(src, ps_2_0_reg_allowed)) {
915         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n",
916                           This->line_no,
917                           debug_print_srcreg(src));
918         set_parse_status(&This->status, PARSE_ERR);
919     }
920     check_legacy_srcmod(This, src->srcmod);
921     check_abs_srcmod(This, src->srcmod);
922     reg = map_oldps_register(src, TRUE);
923     instr->src[num] = reg;
924 }
925 
926 static const struct allowed_reg_type ps_2_x_reg_allowed[] = {
927     { BWRITERSPR_INPUT,         2,  FALSE },
928     { BWRITERSPR_TEMP,         32,  FALSE },
929     { BWRITERSPR_CONST,        32,  FALSE },
930     { BWRITERSPR_CONSTINT,     16,  FALSE },
931     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
932     { BWRITERSPR_PREDICATE,     1,  FALSE },
933     { BWRITERSPR_SAMPLER,      16,  FALSE },
934     { BWRITERSPR_TEXTURE,       8,  FALSE },
935     { BWRITERSPR_LABEL,      2048,  FALSE },
936     { BWRITERSPR_COLOROUT,      4,  FALSE },
937     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
938     { ~0U, 0 } /* End tag */
939 };
940 
941 static void asmparser_srcreg_ps_2_x(struct asm_parser *This,
942                                     struct instruction *instr, int num,
943                                     const struct shader_reg *src) {
944     struct shader_reg reg;
945 
946     if(!check_reg_type(src, ps_2_x_reg_allowed)) {
947         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n",
948                           This->line_no,
949                           debug_print_srcreg(src));
950         set_parse_status(&This->status, PARSE_ERR);
951     }
952     check_legacy_srcmod(This, src->srcmod);
953     check_abs_srcmod(This, src->srcmod);
954     reg = map_oldps_register(src, TRUE);
955     instr->src[num] = reg;
956 }
957 
958 static const struct allowed_reg_type ps_3_reg_allowed[] = {
959     { BWRITERSPR_INPUT,        10,   TRUE },
960     { BWRITERSPR_TEMP,         32,  FALSE },
961     { BWRITERSPR_CONST,       224,  FALSE },
962     { BWRITERSPR_CONSTINT,     16,  FALSE },
963     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
964     { BWRITERSPR_PREDICATE,     1,  FALSE },
965     { BWRITERSPR_SAMPLER,      16,  FALSE },
966     { BWRITERSPR_MISCTYPE,      2,  FALSE }, /* vPos and vFace */
967     { BWRITERSPR_LOOP,          1,  FALSE },
968     { BWRITERSPR_LABEL,      2048,  FALSE },
969     { BWRITERSPR_COLOROUT,      4,  FALSE },
970     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
971     { ~0U, 0 } /* End tag */
972 };
973 
974 static void asmparser_srcreg_ps_3(struct asm_parser *This,
975                                   struct instruction *instr, int num,
976                                   const struct shader_reg *src) {
977     if(!check_reg_type(src, ps_3_reg_allowed)) {
978         asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n",
979                           This->line_no,
980                           debug_print_srcreg(src));
981         set_parse_status(&This->status, PARSE_ERR);
982     }
983     check_loop_swizzle(This, src);
984     check_legacy_srcmod(This, src->srcmod);
985     instr->src[num] = *src;
986 }
987 
988 static void asmparser_dstreg_vs_1(struct asm_parser *This,
989                                   struct instruction *instr,
990                                   const struct shader_reg *dst) {
991     struct shader_reg reg;
992 
993     if(!check_reg_type(dst, vs_1_reg_allowed)) {
994         asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n",
995                           This->line_no,
996                           debug_print_dstreg(dst));
997         set_parse_status(&This->status, PARSE_ERR);
998     }
999     check_ps_dstmod(This, instr->dstmod);
1000     check_shift_dstmod(This, instr->shift);
1001     reg = map_oldvs_register(dst);
1002     instr->dst = reg;
1003     instr->has_dst = TRUE;
1004 }
1005 
1006 static void asmparser_dstreg_vs_2(struct asm_parser *This,
1007                                   struct instruction *instr,
1008                                   const struct shader_reg *dst) {
1009     struct shader_reg reg;
1010 
1011     if(!check_reg_type(dst, vs_2_reg_allowed)) {
1012         asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n",
1013                           This->line_no,
1014                           debug_print_dstreg(dst));
1015         set_parse_status(&This->status, PARSE_ERR);
1016     }
1017     check_ps_dstmod(This, instr->dstmod);
1018     check_shift_dstmod(This, instr->shift);
1019     reg = map_oldvs_register(dst);
1020     instr->dst = reg;
1021     instr->has_dst = TRUE;
1022 }
1023 
1024 static void asmparser_dstreg_vs_3(struct asm_parser *This,
1025                                   struct instruction *instr,
1026                                   const struct shader_reg *dst) {
1027     if(!check_reg_type(dst, vs_3_reg_allowed)) {
1028         asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n",
1029                           This->line_no,
1030                           debug_print_dstreg(dst));
1031         set_parse_status(&This->status, PARSE_ERR);
1032     }
1033     check_ps_dstmod(This, instr->dstmod);
1034     check_shift_dstmod(This, instr->shift);
1035     instr->dst = *dst;
1036     instr->has_dst = TRUE;
1037 }
1038 
1039 static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
1040                                        struct instruction *instr,
1041                                        const struct shader_reg *dst) {
1042     struct shader_reg reg;
1043 
1044     if(!check_reg_type(dst, ps_1_0123_reg_allowed)) {
1045         asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
1046                           This->line_no,
1047                           debug_print_dstreg(dst));
1048         set_parse_status(&This->status, PARSE_ERR);
1049     }
1050     reg = map_oldps_register(dst, FALSE);
1051     instr->dst = reg;
1052     instr->has_dst = TRUE;
1053 }
1054 
1055 static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
1056                                     struct instruction *instr,
1057                                     const struct shader_reg *dst) {
1058     struct shader_reg reg;
1059 
1060     if(!check_reg_type(dst, ps_1_4_reg_allowed)) {
1061         asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
1062                           This->line_no,
1063                           debug_print_dstreg(dst));
1064         set_parse_status(&This->status, PARSE_ERR);
1065     }
1066     reg = map_oldps_register(dst, TRUE);
1067     instr->dst = reg;
1068     instr->has_dst = TRUE;
1069 }
1070 
1071 static void asmparser_dstreg_ps_2(struct asm_parser *This,
1072                                   struct instruction *instr,
1073                                   const struct shader_reg *dst) {
1074     struct shader_reg reg;
1075 
1076     if(!check_reg_type(dst, ps_2_0_reg_allowed)) {
1077         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n",
1078                           This->line_no,
1079                           debug_print_dstreg(dst));
1080         set_parse_status(&This->status, PARSE_ERR);
1081     }
1082     check_shift_dstmod(This, instr->shift);
1083     reg = map_oldps_register(dst, TRUE);
1084     instr->dst = reg;
1085     instr->has_dst = TRUE;
1086 }
1087 
1088 static void asmparser_dstreg_ps_2_x(struct asm_parser *This,
1089                                     struct instruction *instr,
1090                                     const struct shader_reg *dst) {
1091     struct shader_reg reg;
1092 
1093     if(!check_reg_type(dst, ps_2_x_reg_allowed)) {
1094         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n",
1095                           This->line_no,
1096                           debug_print_dstreg(dst));
1097         set_parse_status(&This->status, PARSE_ERR);
1098     }
1099     check_shift_dstmod(This, instr->shift);
1100     reg = map_oldps_register(dst, TRUE);
1101     instr->dst = reg;
1102     instr->has_dst = TRUE;
1103 }
1104 
1105 static void asmparser_dstreg_ps_3(struct asm_parser *This,
1106                                   struct instruction *instr,
1107                                   const struct shader_reg *dst) {
1108     if(!check_reg_type(dst, ps_3_reg_allowed)) {
1109         asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n",
1110                           This->line_no,
1111                           debug_print_dstreg(dst));
1112         set_parse_status(&This->status, PARSE_ERR);
1113     }
1114     check_shift_dstmod(This, instr->shift);
1115     instr->dst = *dst;
1116     instr->has_dst = TRUE;
1117 }
1118 
1119 static void asmparser_predicate_supported(struct asm_parser *This,
1120                                           const struct shader_reg *predicate) {
1121     /* this sets the predicate of the last instruction added to the shader */
1122     if(!This->shader) return;
1123     if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n");
1124     This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE;
1125     This->shader->instr[This->shader->num_instrs - 1]->predicate = *predicate;
1126 }
1127 
1128 static void asmparser_predicate_unsupported(struct asm_parser *This,
1129                                             const struct shader_reg *predicate) {
1130     asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
1131     set_parse_status(&This->status, PARSE_ERR);
1132 }
1133 
1134 static void asmparser_coissue_supported(struct asm_parser *This) {
1135     /* this sets the coissue flag of the last instruction added to the shader */
1136     if(!This->shader) return;
1137     if(This->shader->num_instrs == 0){
1138         asmparser_message(This, "Line %u: Coissue flag on the first shader instruction\n", This->line_no);
1139         set_parse_status(&This->status, PARSE_ERR);
1140     }
1141     This->shader->instr[This->shader->num_instrs-1]->coissue = TRUE;
1142 }
1143 
1144 static void asmparser_coissue_unsupported(struct asm_parser *This) {
1145     asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
1146     set_parse_status(&This->status, PARSE_ERR);
1147 }
1148 
1149 static const struct asmparser_backend parser_vs_1 = {
1150     asmparser_constF,
1151     asmparser_constI,
1152     asmparser_constB,
1153 
1154     asmparser_dstreg_vs_1,
1155     asmparser_srcreg_vs_1,
1156 
1157     asmparser_predicate_unsupported,
1158     asmparser_coissue_unsupported,
1159 
1160     asmparser_dcl_output_unsupported,
1161     asmparser_dcl_input,
1162     asmparser_dcl_sampler_unsupported,
1163 
1164     asmparser_end,
1165 
1166     asmparser_instr,
1167 };
1168 
1169 static const struct asmparser_backend parser_vs_2 = {
1170     asmparser_constF,
1171     asmparser_constI,
1172     asmparser_constB,
1173 
1174     asmparser_dstreg_vs_2,
1175     asmparser_srcreg_vs_2,
1176 
1177     asmparser_predicate_supported,
1178     asmparser_coissue_unsupported,
1179 
1180     asmparser_dcl_output_unsupported,
1181     asmparser_dcl_input,
1182     asmparser_dcl_sampler_unsupported,
1183 
1184     asmparser_end,
1185 
1186     asmparser_instr,
1187 };
1188 
1189 static const struct asmparser_backend parser_vs_3 = {
1190     asmparser_constF,
1191     asmparser_constI,
1192     asmparser_constB,
1193 
1194     asmparser_dstreg_vs_3,
1195     asmparser_srcreg_vs_3,
1196 
1197     asmparser_predicate_supported,
1198     asmparser_coissue_unsupported,
1199 
1200     asmparser_dcl_output,
1201     asmparser_dcl_input,
1202     asmparser_dcl_sampler,
1203 
1204     asmparser_end,
1205 
1206     asmparser_instr,
1207 };
1208 
1209 static const struct asmparser_backend parser_ps_1_0123 = {
1210     asmparser_constF,
1211     asmparser_constI,
1212     asmparser_constB,
1213 
1214     asmparser_dstreg_ps_1_0123,
1215     asmparser_srcreg_ps_1_0123,
1216 
1217     asmparser_predicate_unsupported,
1218     asmparser_coissue_supported,
1219 
1220     asmparser_dcl_output_unsupported,
1221     asmparser_dcl_input_unsupported,
1222     asmparser_dcl_sampler_unsupported,
1223 
1224     asmparser_end,
1225 
1226     asmparser_instr,
1227 };
1228 
1229 static const struct asmparser_backend parser_ps_1_4 = {
1230     asmparser_constF,
1231     asmparser_constI,
1232     asmparser_constB,
1233 
1234     asmparser_dstreg_ps_1_4,
1235     asmparser_srcreg_ps_1_4,
1236 
1237     asmparser_predicate_unsupported,
1238     asmparser_coissue_supported,
1239 
1240     asmparser_dcl_output_unsupported,
1241     asmparser_dcl_input_unsupported,
1242     asmparser_dcl_sampler_unsupported,
1243 
1244     asmparser_end,
1245 
1246     asmparser_instr,
1247 };
1248 
1249 static const struct asmparser_backend parser_ps_2 = {
1250     asmparser_constF,
1251     asmparser_constI,
1252     asmparser_constB,
1253 
1254     asmparser_dstreg_ps_2,
1255     asmparser_srcreg_ps_2,
1256 
1257     asmparser_predicate_unsupported,
1258     asmparser_coissue_unsupported,
1259 
1260     asmparser_dcl_output_unsupported,
1261     asmparser_dcl_input_ps_2,
1262     asmparser_dcl_sampler,
1263 
1264     asmparser_end,
1265 
1266     asmparser_instr,
1267 };
1268 
1269 static const struct asmparser_backend parser_ps_2_x = {
1270     asmparser_constF,
1271     asmparser_constI,
1272     asmparser_constB,
1273 
1274     asmparser_dstreg_ps_2_x,
1275     asmparser_srcreg_ps_2_x,
1276 
1277     asmparser_predicate_supported,
1278     asmparser_coissue_unsupported,
1279 
1280     asmparser_dcl_output_unsupported,
1281     asmparser_dcl_input_ps_2,
1282     asmparser_dcl_sampler,
1283 
1284     asmparser_end,
1285 
1286     asmparser_instr,
1287 };
1288 
1289 static const struct asmparser_backend parser_ps_3 = {
1290     asmparser_constF,
1291     asmparser_constI,
1292     asmparser_constB,
1293 
1294     asmparser_dstreg_ps_3,
1295     asmparser_srcreg_ps_3,
1296 
1297     asmparser_predicate_supported,
1298     asmparser_coissue_unsupported,
1299 
1300     asmparser_dcl_output_unsupported,
1301     asmparser_dcl_input,
1302     asmparser_dcl_sampler,
1303 
1304     asmparser_end,
1305 
1306     asmparser_instr,
1307 };
1308 
1309 static void gen_oldvs_output(struct bwriter_shader *shader) {
1310     record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1311     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1312     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1313     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1314     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1315     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1316     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1317     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1318     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1319     record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, 0, TRUE, OFOG_REG, OFOG_WRITEMASK, TRUE);
1320     record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, 0, TRUE, OPTS_REG, OPTS_WRITEMASK, TRUE);
1321     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1322     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1323 }
1324 
1325 static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
1326     switch(texcoords) {
1327         case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1328             /* fall through */
1329         case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1330             /* fall through */
1331         case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1332             /* fall through */
1333         case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1334             /* fall through */
1335         case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1336             /* fall through */
1337         case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1338             /* fall through */
1339         case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1340             /* fall through */
1341         case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1342     };
1343     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1344     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1345 }
1346 
1347 void create_vs10_parser(struct asm_parser *ret) {
1348     TRACE_(parsed_shader)("vs_1_0\n");
1349 
1350     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1351     if(!ret->shader) {
1352         ERR("Failed to allocate memory for the shader\n");
1353         set_parse_status(&ret->status, PARSE_ERR);
1354         return;
1355     }
1356 
1357     ret->shader->type = ST_VERTEX;
1358     ret->shader->version = BWRITERVS_VERSION(1, 0);
1359     ret->funcs = &parser_vs_1;
1360     gen_oldvs_output(ret->shader);
1361 }
1362 
1363 void create_vs11_parser(struct asm_parser *ret) {
1364     TRACE_(parsed_shader)("vs_1_1\n");
1365 
1366     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1367     if(!ret->shader) {
1368         ERR("Failed to allocate memory for the shader\n");
1369         set_parse_status(&ret->status, PARSE_ERR);
1370         return;
1371     }
1372 
1373     ret->shader->type = ST_VERTEX;
1374     ret->shader->version = BWRITERVS_VERSION(1, 1);
1375     ret->funcs = &parser_vs_1;
1376     gen_oldvs_output(ret->shader);
1377 }
1378 
1379 void create_vs20_parser(struct asm_parser *ret) {
1380     TRACE_(parsed_shader)("vs_2_0\n");
1381 
1382     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1383     if(!ret->shader) {
1384         ERR("Failed to allocate memory for the shader\n");
1385         set_parse_status(&ret->status, PARSE_ERR);
1386         return;
1387     }
1388 
1389     ret->shader->type = ST_VERTEX;
1390     ret->shader->version = BWRITERVS_VERSION(2, 0);
1391     ret->funcs = &parser_vs_2;
1392     gen_oldvs_output(ret->shader);
1393 }
1394 
1395 void create_vs2x_parser(struct asm_parser *ret) {
1396     TRACE_(parsed_shader)("vs_2_x\n");
1397 
1398     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1399     if(!ret->shader) {
1400         ERR("Failed to allocate memory for the shader\n");
1401         set_parse_status(&ret->status, PARSE_ERR);
1402         return;
1403     }
1404 
1405     ret->shader->type = ST_VERTEX;
1406     ret->shader->version = BWRITERVS_VERSION(2, 1);
1407     ret->funcs = &parser_vs_2;
1408     gen_oldvs_output(ret->shader);
1409 }
1410 
1411 void create_vs30_parser(struct asm_parser *ret) {
1412     TRACE_(parsed_shader)("vs_3_0\n");
1413 
1414     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1415     if(!ret->shader) {
1416         ERR("Failed to allocate memory for the shader\n");
1417         set_parse_status(&ret->status, PARSE_ERR);
1418         return;
1419     }
1420 
1421     ret->shader->type = ST_VERTEX;
1422     ret->shader->version = BWRITERVS_VERSION(3, 0);
1423     ret->funcs = &parser_vs_3;
1424 }
1425 
1426 void create_ps10_parser(struct asm_parser *ret) {
1427     TRACE_(parsed_shader)("ps_1_0\n");
1428 
1429     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1430     if(!ret->shader) {
1431         ERR("Failed to allocate memory for the shader\n");
1432         set_parse_status(&ret->status, PARSE_ERR);
1433         return;
1434     }
1435 
1436     ret->shader->type = ST_PIXEL;
1437     ret->shader->version = BWRITERPS_VERSION(1, 0);
1438     ret->funcs = &parser_ps_1_0123;
1439     gen_oldps_input(ret->shader, 4);
1440 }
1441 
1442 void create_ps11_parser(struct asm_parser *ret) {
1443     TRACE_(parsed_shader)("ps_1_1\n");
1444 
1445     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1446     if(!ret->shader) {
1447         ERR("Failed to allocate memory for the shader\n");
1448         set_parse_status(&ret->status, PARSE_ERR);
1449         return;
1450     }
1451 
1452     ret->shader->type = ST_PIXEL;
1453     ret->shader->version = BWRITERPS_VERSION(1, 1);
1454     ret->funcs = &parser_ps_1_0123;
1455     gen_oldps_input(ret->shader, 4);
1456 }
1457 
1458 void create_ps12_parser(struct asm_parser *ret) {
1459     TRACE_(parsed_shader)("ps_1_2\n");
1460 
1461     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1462     if(!ret->shader) {
1463         ERR("Failed to allocate memory for the shader\n");
1464         set_parse_status(&ret->status, PARSE_ERR);
1465         return;
1466     }
1467 
1468     ret->shader->type = ST_PIXEL;
1469     ret->shader->version = BWRITERPS_VERSION(1, 2);
1470     ret->funcs = &parser_ps_1_0123;
1471     gen_oldps_input(ret->shader, 4);
1472 }
1473 
1474 void create_ps13_parser(struct asm_parser *ret) {
1475     TRACE_(parsed_shader)("ps_1_3\n");
1476 
1477     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1478     if(!ret->shader) {
1479         ERR("Failed to allocate memory for the shader\n");
1480         set_parse_status(&ret->status, PARSE_ERR);
1481         return;
1482     }
1483 
1484     ret->shader->type = ST_PIXEL;
1485     ret->shader->version = BWRITERPS_VERSION(1, 3);
1486     ret->funcs = &parser_ps_1_0123;
1487     gen_oldps_input(ret->shader, 4);
1488 }
1489 
1490 void create_ps14_parser(struct asm_parser *ret) {
1491     TRACE_(parsed_shader)("ps_1_4\n");
1492 
1493     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1494     if(!ret->shader) {
1495         ERR("Failed to allocate memory for the shader\n");
1496         set_parse_status(&ret->status, PARSE_ERR);
1497         return;
1498     }
1499 
1500     ret->shader->type = ST_PIXEL;
1501     ret->shader->version = BWRITERPS_VERSION(1, 4);
1502     ret->funcs = &parser_ps_1_4;
1503     gen_oldps_input(ret->shader, 6);
1504 }
1505 
1506 void create_ps20_parser(struct asm_parser *ret) {
1507     TRACE_(parsed_shader)("ps_2_0\n");
1508 
1509     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1510     if(!ret->shader) {
1511         ERR("Failed to allocate memory for the shader\n");
1512         set_parse_status(&ret->status, PARSE_ERR);
1513         return;
1514     }
1515 
1516     ret->shader->type = ST_PIXEL;
1517     ret->shader->version = BWRITERPS_VERSION(2, 0);
1518     ret->funcs = &parser_ps_2;
1519     gen_oldps_input(ret->shader, 8);
1520 }
1521 
1522 void create_ps2x_parser(struct asm_parser *ret) {
1523     TRACE_(parsed_shader)("ps_2_x\n");
1524 
1525     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1526     if(!ret->shader) {
1527         ERR("Failed to allocate memory for the shader\n");
1528         set_parse_status(&ret->status, PARSE_ERR);
1529         return;
1530     }
1531 
1532     ret->shader->type = ST_PIXEL;
1533     ret->shader->version = BWRITERPS_VERSION(2, 1);
1534     ret->funcs = &parser_ps_2_x;
1535     gen_oldps_input(ret->shader, 8);
1536 }
1537 
1538 void create_ps30_parser(struct asm_parser *ret) {
1539     TRACE_(parsed_shader)("ps_3_0\n");
1540 
1541     ret->shader = d3dcompiler_alloc(sizeof(*ret->shader));
1542     if(!ret->shader) {
1543         ERR("Failed to allocate memory for the shader\n");
1544         set_parse_status(&ret->status, PARSE_ERR);
1545         return;
1546     }
1547 
1548     ret->shader->type = ST_PIXEL;
1549     ret->shader->version = BWRITERPS_VERSION(3, 0);
1550     ret->funcs = &parser_ps_3;
1551 }
1552