/
mojoshader_assembler.c
1789 lines (1495 loc) · 51.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
/**
* MojoShader; generate shader programs from bytecode of compiled
* Direct3D shaders.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
13
14
15
16
17
18
19
#if DEBUG_ASSEMBLY_PARSER
#define print_debug_token(token, len, val) \
MOJOSHADER_print_debug_token("ASSEMBLER", token, len, val)
#else
#define print_debug_token(token, len, val)
#endif
20
21
22
23
24
25
26
typedef struct SourcePos
{
const char *filename;
uint32 line;
} SourcePos;
27
28
// Context...this is state that changes as we assemble a shader...
29
typedef struct Context
30
{
31
32
int isfail;
int out_of_memory;
33
34
35
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
36
37
int error_count;
ErrorList *errors;
38
Preprocessor *preprocessor;
39
MOJOSHADER_parsePhase parse_phase;
40
41
42
MOJOSHADER_shaderType shader_type;
uint8 major_ver;
uint8 minor_ver;
43
44
45
46
47
48
49
int pushedback;
const char *token; // assembler token!
unsigned int tokenlen; // assembler token!
Token tokenval; // assembler token!
uint32 version_token; // bytecode token!
uint32 tokenbuf[16]; // bytecode tokens!
int tokenbufpos; // bytecode tokens!
50
DestArgInfo dest_arg;
51
uint32 *output;
52
SourcePos *token_to_source;
53
54
55
uint8 *ctab;
uint32 ctab_len;
uint32 ctab_allocation;
56
57
size_t output_len;
size_t output_allocation;
58
} Context;
59
60
61
62
// Convenience functions for allocators...
63
static inline void out_of_memory(Context *ctx)
64
{
65
ctx->isfail = ctx->out_of_memory = 1;
66
67
68
69
70
71
72
73
74
75
} // out_of_memory
static inline void *Malloc(Context *ctx, const size_t len)
{
void *retval = ctx->malloc((int) len, ctx->malloc_data);
if (retval == NULL)
out_of_memory(ctx);
return retval;
} // Malloc
76
77
78
static inline char *StrDup(Context *ctx, const char *str)
{
char *retval = (char *) Malloc(ctx, strlen(str) + 1);
79
if (retval != NULL)
80
81
82
83
strcpy(retval, str);
return retval;
} // StrDup
84
85
86
87
88
89
static inline void Free(Context *ctx, void *ptr)
{
if (ptr != NULL) // check for NULL in case of dumb free() impl.
ctx->free(ptr, ctx->malloc_data);
} // Free
90
91
static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void failf(Context *ctx, const char *fmt, ...)
92
{
93
94
95
96
const char *fname = NULL;
unsigned int linenum = 0;
int error_position = 0;
97
98
ctx->isfail = 1;
99
100
101
102
103
104
switch (ctx->parse_phase)
{
case MOJOSHADER_PARSEPHASE_NOTSTARTED:
error_position = -2;
break;
case MOJOSHADER_PARSEPHASE_WORKING:
105
106
fname = preprocessor_sourcepos(ctx->preprocessor, &linenum);
error_position = (int) linenum;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
break;
case MOJOSHADER_PARSEPHASE_DONE:
error_position = -1;
break;
default:
assert(0 && "Unexpected value");
return;
} // switch
ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList));
if (error == NULL)
return;
char scratch = 0;
va_list ap;
va_start(ap, fmt);
const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap);
va_end(ap);
char *failstr = (char *) Malloc(ctx, len + 1);
if (failstr == NULL)
Free(ctx, error);
else
130
131
{
va_start(ap, fmt);
132
vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
133
134
va_end(ap);
135
136
137
error->error.error = failstr;
error->error.filename = fname ? StrDup(ctx, fname) : NULL;
error->error.error_position = error_position;
138
error->next = NULL;
139
140
ErrorList *prev = NULL;
141
142
ErrorList *item = ctx->errors;
while (item != NULL)
143
{
144
prev = item;
145
item = item->next;
146
147
} // while
148
if (prev == NULL)
149
ctx->errors = error;
150
151
else
prev->next = error;
152
153
154
ctx->error_count++;
} // else
155
156
} // failf
157
static inline void fail(Context *ctx, const char *reason)
158
{
159
failf(ctx, "%s", reason);
160
161
162
163
} // fail
static inline int isfail(const Context *ctx)
{
164
return ctx->isfail;
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
} // isfail
// Shader model version magic...
static inline uint32 ver_ui32(const uint8 major, const uint8 minor)
{
return ( (((uint32) major) << 16) | (((minor) == 0xFF) ? 0 : (minor)) );
} // version_ui32
static inline int shader_version_atleast(const Context *ctx, const uint8 maj,
const uint8 min)
{
return (ver_ui32(ctx->major_ver, ctx->minor_ver) >= ver_ui32(maj, min));
} // shader_version_atleast
static inline int shader_is_pixel(const Context *ctx)
{
return (ctx->shader_type == MOJOSHADER_TYPE_PIXEL);
} // shader_is_pixel
static inline int shader_is_vertex(const Context *ctx)
{
return (ctx->shader_type == MOJOSHADER_TYPE_VERTEX);
} // shader_is_vertex
191
192
static inline void pushback(Context *ctx)
{
193
194
195
#if DEBUG_ASSEMBLY_PARSER
printf("ASSEMBLER PUSHBACK\n");
#endif
196
197
198
199
200
201
assert(!ctx->pushedback);
ctx->pushedback = 1;
} // pushback
static Token _nexttoken(Context *ctx)
{
202
while (1)
203
{
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
ctx->token = preprocessor_nexttoken(ctx->preprocessor, &ctx->tokenlen,
&ctx->tokenval);
if (preprocessor_outofmemory(ctx->preprocessor))
{
out_of_memory(ctx);
ctx->tokenval = TOKEN_EOI;
ctx->token = NULL;
ctx->tokenlen = 0;
break;
} // if
if (ctx->tokenval == TOKEN_PREPROCESSING_ERROR)
{
fail(ctx, ctx->token);
continue;
} // else
break;
} // while
224
225
226
227
228
229
230
231
232
return ctx->tokenval;
} // _nexttoken
static Token nexttoken(Context *ctx)
{
if (ctx->pushedback)
{
233
print_debug_token(ctx->token, ctx->tokenlen, ctx->tokenval);
234
235
236
237
238
ctx->pushedback = 0;
return ctx->tokenval;
} // if
Token token = _nexttoken(ctx);
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
while (token == ((Token) '\n'))
token = _nexttoken(ctx); // skip endlines.
if (token == ((Token) ';')) // single line comment in assembler.
{
do
{
token = _nexttoken(ctx);
} while ((token != ((Token) '\n')) && (token != TOKEN_EOI));
while (token == ((Token) '\n'))
token = _nexttoken(ctx); // skip endlines.
} // if
254
print_debug_token(ctx->token, ctx->tokenlen, ctx->tokenval);
255
256
257
258
return token;
} // nexttoken
259
260
static inline void add_token_sourcepos(Context *ctx, const size_t idx)
{
261
262
263
unsigned int pos = 0;
const char *fname = preprocessor_sourcepos(ctx->preprocessor, &pos);
ctx->token_to_source[idx].line = pos;
264
ctx->token_to_source[idx].filename = fname; // cached in preprocessor!
265
266
267
} // add_token_sourcepos
268
269
270
271
272
static void output_token_noswap(Context *ctx, const uint32 token)
{
if (isfail(ctx))
return;
273
274
275
276
if (ctx->output_len >= ctx->output_allocation)
{
const size_t output_alloc_bump = 1024; // that's tokens, not bytes.
const size_t newsize = ctx->output_allocation + output_alloc_bump;
277
278
279
void *ptr;
ptr = Malloc(ctx, newsize * sizeof (uint32));
280
281
282
283
284
285
if (ptr == NULL)
return;
if (ctx->output_len > 0)
memcpy(ptr, ctx->output, ctx->output_len * sizeof (uint32));
Free(ctx, ctx->output);
ctx->output = (uint32 *) ptr;
286
287
ptr = Malloc(ctx, newsize * sizeof (SourcePos));
288
289
290
if (ptr == NULL)
return;
if (ctx->output_len > 0)
291
292
293
memcpy(ptr, ctx->token_to_source, ctx->output_len * sizeof (SourcePos));
Free(ctx, ctx->token_to_source);
ctx->token_to_source = (SourcePos *) ptr;
294
295
ctx->output_allocation = newsize;
296
297
} // if
298
ctx->output[ctx->output_len] = token;
299
add_token_sourcepos(ctx, ctx->output_len);
300
ctx->output_len++;
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
} // output_token_noswap
static inline void output_token(Context *ctx, const uint32 token)
{
output_token_noswap(ctx, SWAP32(token));
} // output_token
static void output_comment_bytes(Context *ctx, const uint8 *buf, size_t len)
{
if (len > (0xFFFF * 4)) // length is stored as token count, in 16 bits.
fail(ctx, "Comment field is too big");
else if (!isfail(ctx))
{
const uint32 tokencount = (len / 4) + ((len % 4) ? 1 : 0);
output_token(ctx, 0xFFFE | (tokencount << 16));
while (len >= 4)
{
output_token_noswap(ctx, *((const uint32 *) buf));
len -= 4;
buf += 4;
} // while
if (len > 0) // handle spillover...
{
union { uint8 ui8[4]; uint32 ui32; } overflow;
overflow.ui32 = 0;
memcpy(overflow.ui8, buf, len);
output_token_noswap(ctx, overflow.ui32);
} // if
} // else if
} // output_comment_bytes
static inline void output_comment_string(Context *ctx, const char *str)
{
output_comment_bytes(ctx, (const uint8 *) str, strlen(str));
} // output_comment_string
342
static int require_comma(Context *ctx)
343
{
344
345
const Token token = nexttoken(ctx);
if (token != ((Token) ','))
346
{
347
348
fail(ctx, "Comma expected");
return 0;
349
} // if
350
351
return 1;
} // require_comma
352
353
354
static int check_token_segment(Context *ctx, const char *str)
355
{
356
357
358
359
360
361
362
363
// !!! FIXME: these are case-insensitive, right?
const size_t len = strlen(str);
if ( (ctx->tokenlen < len) || (strncasecmp(ctx->token, str, len) != 0) )
return 0;
ctx->token += len;
ctx->tokenlen -= len;
return 1;
} // check_token_segment
364
365
366
static int check_token(Context *ctx, const char *str)
367
{
368
369
const size_t len = strlen(str);
if ( (ctx->tokenlen != len) || (strncasecmp(ctx->token, str, len) != 0) )
370
return 0;
371
372
ctx->token += len;
ctx->tokenlen = 0;
373
return 1;
374
} // check_token
375
376
377
static int ui32fromtoken(Context *ctx, uint32 *_val)
378
{
379
380
381
382
383
384
int i;
for (i = 0; i < ctx->tokenlen; i++)
{
if ((ctx->token[i] < '0') || (ctx->token[i] > '9'))
break;
} // for
385
386
if (i == 0)
387
{
388
389
*_val = 0;
return 0;
390
391
} // if
392
393
394
395
const int len = i;
uint32 val = 0;
uint32 mult = 1;
while (i--)
396
{
397
398
399
val += ((uint32) (ctx->token[i] - '0')) * mult;
mult *= 10;
} // while
400
401
402
ctx->token += len;
ctx->tokenlen -= len;
403
404
*_val = val;
405
return 1;
406
} // ui32fromtoken
407
408
409
410
static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum)
{
411
412
413
if (nexttoken(ctx) != TOKEN_IDENTIFIER)
{
fail(ctx, "Expected register");
414
return 0;
415
} // if
416
417
418
419
int neednum = 1;
int regnum = 0;
RegisterType regtype = REG_TYPE_TEMP;
420
421
422
423
// Watch out for substrings! oDepth must be checked before oD, since
// the latter will match either case.
if (check_token_segment(ctx, "oDepth"))
424
425
426
427
{
regtype = REG_TYPE_DEPTHOUT;
neednum = 0;
} // else if
428
else if (check_token_segment(ctx, "vFace"))
429
{
430
431
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_FACE;
432
433
neednum = 0;
} // else if
434
else if (check_token_segment(ctx, "vPos"))
435
436
437
438
439
{
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_POSITION;
neednum = 0;
} // else if
440
else if (check_token_segment(ctx, "oPos"))
441
442
443
444
445
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_POSITION;
neednum = 0;
} // else if
446
else if (check_token_segment(ctx, "oFog"))
447
448
449
450
451
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_FOG;
neednum = 0;
} // else if
452
else if (check_token_segment(ctx, "oPts"))
453
454
455
456
457
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_POINT_SIZE;
neednum = 0;
} // else if
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
else if (check_token_segment(ctx, "aL"))
{
regtype = REG_TYPE_LOOP;
neednum = 0;
} // else if
else if (check_token_segment(ctx, "oC"))
regtype = REG_TYPE_COLOROUT;
else if (check_token_segment(ctx, "oT"))
regtype = REG_TYPE_OUTPUT;
else if (check_token_segment(ctx, "oD"))
regtype = REG_TYPE_ATTROUT;
else if (check_token_segment(ctx, "r"))
regtype = REG_TYPE_TEMP;
else if (check_token_segment(ctx, "v"))
regtype = REG_TYPE_INPUT;
else if (check_token_segment(ctx, "c"))
regtype = REG_TYPE_CONST;
else if (check_token_segment(ctx, "i"))
regtype = REG_TYPE_CONSTINT;
else if (check_token_segment(ctx, "b"))
regtype = REG_TYPE_CONSTBOOL;
else if (check_token_segment(ctx, "s"))
regtype = REG_TYPE_SAMPLER;
else if (check_token_segment(ctx, "l"))
regtype = REG_TYPE_LABEL;
else if (check_token_segment(ctx, "p"))
regtype = REG_TYPE_PREDICATE;
else if (check_token_segment(ctx, "o"))
regtype = REG_TYPE_OUTPUT;
else if (check_token_segment(ctx, "a"))
regtype = REG_TYPE_ADDRESS;
else if (check_token_segment(ctx, "t"))
regtype = REG_TYPE_ADDRESS;
491
492
493
494
495
//case REG_TYPE_TEMPFLOAT16: // !!! FIXME: don't know this asm string
else
{
496
497
498
499
fail(ctx, "expected register type");
regtype = REG_TYPE_CONST;
regnum = 0;
neednum = 0;
500
501
} // else
502
503
// "c[5]" is the same as "c5", so if the token is done, see if next is '['.
if ((neednum) && (ctx->tokenlen == 0))
504
{
505
if (nexttoken(ctx) == ((Token) '['))
506
neednum = 0; // don't need a number on register name itself.
507
pushback(ctx);
508
509
} // if
510
511
if (neednum)
{
512
uint32 ui32 = 0;
513
if (!ui32fromtoken(ctx, &ui32))
514
fail(ctx, "Invalid register index");
515
regnum = (int) ui32;
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
} // if
// split up REG_TYPE_CONST
if (regtype == REG_TYPE_CONST)
{
if (regnum < 2048)
{
regtype = REG_TYPE_CONST;
regnum -= 0;
} // if
else if (regnum < 4096)
{
regtype = REG_TYPE_CONST2;
regnum -= 2048;
} // if
else if (regnum < 6144)
{
regtype = REG_TYPE_CONST3;
regnum -= 4096;
} // if
else if (regnum < 8192)
{
regtype = REG_TYPE_CONST4;
regnum -= 6144;
} // if
else
{
543
fail(ctx, "Invalid const register index");
544
545
546
547
548
549
} // else
} // if
*rtype = regtype;
*rnum = regnum;
550
return 1;
551
552
553
} // parse_register_name
554
static void set_result_shift(Context *ctx, DestArgInfo *info, const int val)
555
{
556
if (info->result_shift != 0)
557
fail(ctx, "Multiple result shift modifiers");
558
559
info->result_shift = val;
} // set_result_shift
560
561
562
static int parse_destination_token(Context *ctx)
563
{
564
DestArgInfo *info = &ctx->dest_arg;
565
memset(info, '\0', sizeof (DestArgInfo));
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
// parse_instruction_token() sets ctx->token to the end of the instruction
// so we can see if there are destination modifiers on the instruction
// itself...
int invalid_modifier = 0;
while ((ctx->tokenlen > 0) && (!invalid_modifier))
{
if (check_token_segment(ctx, "_x2"))
set_result_shift(ctx, info, 0x1);
else if (check_token_segment(ctx, "_x4"))
set_result_shift(ctx, info, 0x2);
else if (check_token_segment(ctx, "_x8"))
set_result_shift(ctx, info, 0x3);
else if (check_token_segment(ctx, "_d8"))
set_result_shift(ctx, info, 0xD);
else if (check_token_segment(ctx, "_d4"))
set_result_shift(ctx, info, 0xE);
else if (check_token_segment(ctx, "_d2"))
set_result_shift(ctx, info, 0xF);
else if (check_token_segment(ctx, "_sat"))
588
info->result_mod |= MOD_SATURATE;
589
else if (check_token_segment(ctx, "_pp"))
590
info->result_mod |= MOD_PP;
591
else if (check_token_segment(ctx, "_centroid"))
592
593
info->result_mod |= MOD_CENTROID;
else
594
invalid_modifier = 1;
595
596
} // while
597
598
if (invalid_modifier)
fail(ctx, "Invalid destination modifier");
599
600
// !!! FIXME: predicates.
601
if (nexttoken(ctx) == ((Token) '('))
602
603
fail(ctx, "Predicates unsupported at this time"); // !!! FIXME: ...
604
605
pushback(ctx); // parse_register_name calls nexttoken().
606
parse_register_name(ctx, &info->regtype, &info->regnum);
607
608
609
// parse_register_name() can't check this: dest regs might have modifiers.
if (ctx->tokenlen > 0)
fail(ctx, "invalid register name");
610
611
612
// !!! FIXME: can dest registers do relative addressing?
613
int invalid_writemask = 0;
614
int implicit_writemask = 0;
615
if (nexttoken(ctx) != ((Token) '.'))
616
{
617
implicit_writemask = 1;
618
619
620
621
info->writemask = 0xF;
info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 1;
pushback(ctx); // no explicit writemask; do full mask.
} // if
622
623
624
625
// !!! FIXME: Cg generates code with oDepth.z ... this is a bug, I think.
//else if (scalar_register(ctx->shader_type, info->regtype, info->regnum))
else if ( (scalar_register(ctx->shader_type, info->regtype, info->regnum)) && (info->regtype != REG_TYPE_DEPTHOUT) )
626
fail(ctx, "Writemask specified for scalar register");
627
else if (nexttoken(ctx) != TOKEN_IDENTIFIER)
628
invalid_writemask = 1;
629
630
else
{
631
632
633
634
635
636
// !!! FIXME: is out-of-order okay (yxzw instead of xyzw?)
char tokenbytes[5] = { '\0', '\0', '\0', '\0', '\0' };
const unsigned int tokenlen = ctx->tokenlen;
memcpy(tokenbytes, ctx->token, ((tokenlen < 4) ? tokenlen : 4));
char *ptr = tokenbytes;
637
info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 0;
638
639
640
641
if (*ptr == 'x') { info->writemask0 = 1; ptr++; }
if (*ptr == 'y') { info->writemask1 = 1; ptr++; }
if (*ptr == 'z') { info->writemask2 = 1; ptr++; }
if (*ptr == 'w') { info->writemask3 = 1; ptr++; }
642
if ((ptr == ctx->token) && (shader_is_pixel(ctx)))
643
{
644
645
646
647
if (*ptr == 'r') { info->writemask0 = 1; ptr++; }
if (*ptr == 'g') { info->writemask1 = 1; ptr++; }
if (*ptr == 'b') { info->writemask2 = 1; ptr++; }
if (*ptr == 'a') { info->writemask3 = 1; ptr++; }
648
649
650
} // if
if (*ptr != '\0')
651
invalid_writemask = 1;
652
653
654
655
656
657
658
info->writemask = ( ((info->writemask0 & 0x1) << 0) |
((info->writemask1 & 0x1) << 1) |
((info->writemask2 & 0x1) << 2) |
((info->writemask3 & 0x1) << 3) );
} // else
659
660
661
if (invalid_writemask)
fail(ctx, "Invalid writemask");
662
663
664
665
666
// !!! FIXME: Cg generates code with oDepth.z ... this is a bug, I think.
if (info->regtype == REG_TYPE_DEPTHOUT)
{
if ( (!implicit_writemask) && ((info->writemask0 + info->writemask1 +
info->writemask2 + info->writemask3) > 1) )
667
fail(ctx, "Writemask specified for scalar register");
668
669
} // if
670
671
672
info->orig_writemask = info->writemask;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
673
674
675
676
{
fail(ctx, "Too many tokens");
return 1;
} // if
677
678
ctx->tokenbuf[ctx->tokenbufpos++] =
679
( ((((uint32) 1)) << 31) |
680
681
682
683
((((uint32) info->regnum) & 0x7ff) << 0) |
((((uint32) info->relative) & 0x1) << 13) |
((((uint32) info->result_mod) & 0xF) << 20) |
((((uint32) info->result_shift) & 0xF) << 24) |
684
((((uint32) info->writemask) & 0xF) << 16) |
685
686
687
688
689
690
691
((((uint32) info->regtype) & 0x7) << 28) |
((((uint32) info->regtype) & 0x18) << 8) );
return 1;
} // parse_destination_token
692
693
694
static void set_source_mod(Context *ctx, const int negate,
const SourceMod norm, const SourceMod negated,
SourceMod *srcmod)
695
{
696
697
698
699
700
if ( (*srcmod != SRCMOD_NONE) || (negate && (negated == SRCMOD_NONE)) )
fail(ctx, "Incompatible source modifiers");
else
*srcmod = ((negate) ? negated : norm);
} // set_source_mod
701
702
703
static int parse_source_token_maybe_relative(Context *ctx, const int relok)
704
{
705
706
707
int retval = 1;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
708
709
710
711
{
fail(ctx, "Too many tokens");
return 0;
} // if
712
713
// mark this now, so optional relative addressing token is placed second.
714
715
uint32 *outtoken = &ctx->tokenbuf[ctx->tokenbufpos++];
*outtoken = 0;
716
717
718
SourceMod srcmod = SRCMOD_NONE;
int negate = 0;
719
720
721
722
723
724
725
Token token = nexttoken(ctx);
if (token == ((Token) '!'))
srcmod = SRCMOD_NOT;
else if (token == ((Token) '-'))
negate = 1;
else if ( (token == TOKEN_INT_LITERAL) && (check_token(ctx, "1")) )
726
{
727
728
if (nexttoken(ctx) != ((Token) '-'))
fail(ctx, "Unexpected token");
729
730
731
732
else
srcmod = SRCMOD_COMPLEMENT;
} // else
else
733
{
734
pushback(ctx);
735
} // else
736
737
738
RegisterType regtype;
int regnum;
739
parse_register_name(ctx, ®type, ®num);
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
if (ctx->tokenlen > 0)
{
if (check_token_segment(ctx, "_bias"))
set_source_mod(ctx, negate, SRCMOD_BIAS, SRCMOD_BIASNEGATE, &srcmod);
else if (check_token_segment(ctx, "_bx2"))
set_source_mod(ctx, negate, SRCMOD_SIGN, SRCMOD_SIGNNEGATE, &srcmod);
else if (check_token_segment(ctx, "_x2"))
set_source_mod(ctx, negate, SRCMOD_X2, SRCMOD_X2NEGATE, &srcmod);
else if (check_token_segment(ctx, "_dz"))
set_source_mod(ctx, negate, SRCMOD_DZ, SRCMOD_NONE, &srcmod);
else if (check_token_segment(ctx, "_dw"))
set_source_mod(ctx, negate, SRCMOD_DW, SRCMOD_NONE, &srcmod);
else if (check_token_segment(ctx, "_abs"))
set_source_mod(ctx, negate, SRCMOD_ABS, SRCMOD_ABSNEGATE, &srcmod);
else
fail(ctx, "Invalid source modifier");
} // if
758
759
uint32 relative = 0;
760
if (nexttoken(ctx) != ((Token) '['))
761
762
763
pushback(ctx); // not relative addressing?
else
{
764
765
766
767
768
769
if (!relok)
fail(ctx, "Relative addressing not permitted here.");
else
retval++;
parse_source_token_maybe_relative(ctx, 0);
770
relative = 1;
771
772
if (nexttoken(ctx) != ((Token) '+'))
773
774
775
pushback(ctx);
else
{
776
777
// !!! FIXME: maybe c3[a0.x + 5] is legal and becomes c[a0.x + 8] ?
if (regnum != 0)
778
fail(ctx, "Relative addressing with explicit register number.");
779
780
uint32 ui32 = 0;
781
782
783
784
if ( (nexttoken(ctx) != TOKEN_INT_LITERAL) ||
(!ui32fromtoken(ctx, &ui32)) ||
(ctx->tokenlen != 0) )
{
785
fail(ctx, "Invalid relative addressing offset");
786
} // if
787
788
789
regnum += (int) ui32;
} // else
790
if (nexttoken(ctx) != ((Token) ']'))
791
fail(ctx, "Expected ']'");
792
} // else
793
794
int invalid_swizzle = 0;
795
uint32 swizzle = 0;
796
if (nexttoken(ctx) != ((Token) '.'))
797
798
799
800
{
swizzle = 0xE4; // 0xE4 == 11100100 ... 0 1 2 3. No swizzle.
pushback(ctx); // no explicit writemask; do full mask.
} // if
801
else if (scalar_register(ctx->shader_type, regtype, regnum))
802
fail(ctx, "Swizzle specified for scalar register");
803
else if (nexttoken(ctx) != TOKEN_IDENTIFIER)
804
invalid_swizzle = 1;
805
806
else
{
807
808
809
810
char tokenbytes[5] = { '\0', '\0', '\0', '\0', '\0' };
const unsigned int tokenlen = ctx->tokenlen;
memcpy(tokenbytes, ctx->token, ((tokenlen < 4) ? tokenlen : 4));
811
// deal with shortened form (.x = .xxxx, etc).
812
813
814
815
816
817
818
if (tokenlen == 1)
tokenbytes[1] = tokenbytes[2] = tokenbytes[3] = tokenbytes[0];
else if (tokenlen == 2)
tokenbytes[2] = tokenbytes[3] = tokenbytes[1];
else if (tokenlen == 3)
tokenbytes[3] = tokenbytes[2];
else if (tokenlen != 4)
819
invalid_swizzle = 1;
820
tokenbytes[4] = '\0';
821
822
uint32 val = 0;
823
824
int saw_xyzw = 0;
int saw_rgba = 0;
825
int i;
826
827
for (i = 0; i < 4; i++)
{
828
const int component = (int) tokenbytes[i];
829
830
831
832
833
834
835
836
837
838
switch (component)
{
case 'x': val = 0; saw_xyzw = 1; break;
case 'y': val = 1; saw_xyzw = 1; break;
case 'z': val = 2; saw_xyzw = 1; break;
case 'w': val = 3; saw_xyzw = 1; break;
case 'r': val = 0; saw_rgba = 1; break;
case 'g': val = 1; saw_rgba = 1; break;
case 'b': val = 2; saw_rgba = 1; break;
case 'a': val = 3; saw_rgba = 1; break;
839
default: invalid_swizzle = 1; break;
840
841
842
} // switch
swizzle |= (val << (i * 2));
} // for
843
844
if (saw_xyzw && saw_rgba)
845
invalid_swizzle = 1;
846
847
else if (saw_rgba && !shader_is_pixel(ctx))
invalid_swizzle = 1;
848
} // else
849
850
851
852
if (invalid_swizzle)
fail(ctx, "Invalid swizzle");
853
854
855
856
857
858
859
*outtoken = ( ((((uint32) 1)) << 31) |
((((uint32) regnum) & 0x7ff) << 0) |
((((uint32) relative) & 0x1) << 13) |
((((uint32) swizzle) & 0xFF) << 16) |
((((uint32) srcmod) & 0xF) << 24) |
((((uint32) regtype) & 0x7) << 28) |
((((uint32) regtype) & 0x18) << 8) );
860
861
862
return retval;
} // parse_source_token_maybe_relative
863
864
865
static inline int parse_source_token(Context *ctx)
866
{
867
868
return parse_source_token_maybe_relative(ctx, 1);
} // parse_source_token
869
870
871
872
static int parse_args_NULL(Context *ctx)
{
873
return 1;
874
} // parse_args_NULL
875
876
877
static int parse_num(Context *ctx, const int floatok, uint32 *value)
878
879
{
union { float f; int32 si32; uint32 ui32; } cvt;
880
881
882
883
884
885
886
887
int negative = 0;
Token token = nexttoken(ctx);
if (token == ((Token) '-'))
{
negative = 1;
token = nexttoken(ctx);
} // if
888
889
if (token == TOKEN_INT_LITERAL)
890
{
891
892
int d = 0;
sscanf(ctx->token, "%d", &d);
893
894
895
896
if (floatok)
cvt.f = (float) ((negative) ? -d : d);
else
cvt.si32 = (int32) ((negative) ? -d : d);
897
898
} // if
else if (token == TOKEN_FLOAT_LITERAL)
899
{
900
if (!floatok)
901
{
902
903
904
fail(ctx, "Expected whole number");
*value = 0;
return 0;
905
} // if
906
sscanf(ctx->token, "%f", &cvt.f);
907
908
if (negative)
cvt.f = -cvt.f;
909
910
911
912
913
914
} // if
else
{
fail(ctx, "Expected number");
*value = 0;
return 0;
915
} // else
916
917
*value = cvt.ui32;
918
return 1;
919
920
921
922
923
} // parse_num
static int parse_args_DEFx(Context *ctx, const int isflt)
{
924
925
926
927
928
929
930
931
932
parse_destination_token(ctx);
require_comma(ctx);
parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]);
require_comma(ctx);
parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]);
require_comma(ctx);
parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]);
require_comma(ctx);
parse_num(ctx, isflt, &ctx->tokenbuf[ctx->tokenbufpos++]);
933
934
return 6;
} // parse_args_DEFx
935
936
937
938
939
940
static int parse_args_DEF(Context *ctx)
{
return parse_args_DEFx(ctx, 1);
} // parse_args_DEF
941
942
943
944
945
946
static int parse_args_DEFI(Context *ctx)
{
return parse_args_DEFx(ctx, 0);
} // parse_args_DEFI
947
948
949
950
static int parse_args_DEFB(Context *ctx)
{
951
952
parse_destination_token(ctx);
require_comma(ctx);
953
954
955
956
957
958
959
960
// !!! FIXME: do a TOKEN_TRUE and TOKEN_FALSE? Is this case-sensitive?
const Token token = nexttoken(ctx);
int bad = 0;
if (token != TOKEN_IDENTIFIER)
bad = 1;
else if (check_token_segment(ctx, "true"))
961
ctx->tokenbuf[ctx->tokenbufpos++] = 1;
962
else if (check_token_segment(ctx, "false"))
963
964
ctx->tokenbuf[ctx->tokenbufpos++] = 0;
else
965
966
967
968
969
970
bad = 1;
if (ctx->tokenlen != 0)
bad = 1;
if (bad)
971
fail(ctx, "Expected 'true' or 'false'");
972
973
974
return 3;
} // parse_args_DEFB
975
976
977
static int parse_dcl_usage(Context *ctx, uint32 *val, int *issampler)
978
979
{
int i;
980
static const char *samplerusagestrs[] = { "_2d", "_cube", "_volume" };
981
static const char *usagestrs[] = {
982
983
984
"_position", "_blendweight", "_blendindices", "_normal", "_psize",
"_texcoord", "_tangent", "_binormal", "_tessfactor", "_positiont",
"_color", "_fog", "_depth", "_sample"
985
};
986
987
for (i = 0; i < STATICARRAYLEN(usagestrs); i++)
988
{
989
if (check_token_segment(ctx, usagestrs[i]))
990
{
991
992
*issampler = 0;
*val = i;
993
return 1;
994
} // if
995
} // for
996
997
for (i = 0; i < STATICARRAYLEN(samplerusagestrs); i++)
998
{
999
if (check_token_segment(ctx, samplerusagestrs[i]))
1000
{