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