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