Skip to content

Latest commit

 

History

History
2070 lines (1755 loc) · 58 KB

mojoshader_assembler.c

File metadata and controls

2070 lines (1755 loc) · 58 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"
Dec 10, 2008
Dec 10, 2008
13
#define DEBUG_TOKENIZER 0
Dec 10, 2008
Dec 10, 2008
15
// !!! FIXME: no #define support yet.
Dec 13, 2008
Dec 13, 2008
17
typedef struct TokenizerContext
Dec 13, 2008
Dec 13, 2008
18
19
20
21
22
23
24
{
const char *source;
int on_endline;
unsigned int linenum;
char prevchar;
char token[64];
char pushedback;
Dec 13, 2008
Dec 13, 2008
25
} TokenizerContext;
Dec 13, 2008
Dec 13, 2008
26
27
Feb 3, 2009
Feb 3, 2009
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...
Feb 3, 2009
Feb 3, 2009
36
typedef struct Context
Feb 3, 2009
Feb 3, 2009
38
39
40
int isfail;
int out_of_memory;
int eof;
41
42
43
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
Feb 3, 2009
Feb 3, 2009
44
45
int error_count;
ErrorList *errors;
Dec 13, 2008
Dec 13, 2008
46
TokenizerContext tctx;
Dec 19, 2008
Dec 19, 2008
47
MOJOSHADER_parsePhase parse_phase;
48
49
50
MOJOSHADER_shaderType shader_type;
uint8 major_ver;
uint8 minor_ver;
Dec 20, 2008
Dec 20, 2008
51
uint32 version_token;
52
53
54
uint32 tokenbuf[16];
int tokenbufpos;
DestArgInfo dest_arg;
Dec 8, 2008
Dec 8, 2008
55
uint32 *output;
Feb 3, 2009
Feb 3, 2009
56
SourcePos *token_to_source;
Dec 20, 2008
Dec 20, 2008
57
58
59
uint8 *ctab;
uint32 ctab_len;
uint32 ctab_allocation;
Dec 8, 2008
Dec 8, 2008
60
61
size_t output_len;
size_t output_allocation;
Feb 3, 2009
Feb 3, 2009
62
} Context;
63
64
65
66
// Convenience functions for allocators...
Feb 3, 2009
Feb 3, 2009
67
static inline void out_of_memory(Context *ctx)
Feb 3, 2009
Feb 3, 2009
69
ctx->isfail = ctx->out_of_memory = 1;
70
71
72
73
74
75
76
77
78
79
} // 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
Feb 3, 2009
Feb 3, 2009
80
81
82
83
84
85
86
87
88
89
static inline char *StrDup(Context *ctx, const char *str)
{
char *retval = (char *) Malloc(ctx, strlen(str) + 1);
if (retval == NULL)
out_of_memory(ctx);
else
strcpy(retval, str);
return retval;
} // StrDup
90
91
92
93
94
95
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
Feb 3, 2009
Feb 3, 2009
96
97
static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void failf(Context *ctx, const char *fmt, ...)
Feb 3, 2009
Feb 3, 2009
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
const char *fname = NULL;
unsigned int linenum = 0;
int error_position = 0;
switch (ctx->parse_phase)
{
case MOJOSHADER_PARSEPHASE_NOTSTARTED:
error_position = -2;
break;
case MOJOSHADER_PARSEPHASE_WORKING:
// !!! FIXME: fname == base source file if output_pos == 0.
if (ctx->output_len > 0)
{
const size_t idx = ctx->output_len - 1;
linenum = ctx->token_to_source[idx].line;
fname = ctx->token_to_source[idx].filename;
} // if
error_position = linenum;
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
140
141
{
va_start(ap, fmt);
Feb 3, 2009
Feb 3, 2009
142
vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
143
144
va_end(ap);
Feb 3, 2009
Feb 3, 2009
145
146
147
148
149
150
151
error->error.error = failstr;
error->error.filename = fname ? StrDup(ctx, fname) : NULL;
error->error.error_position = error_position;
ErrorList *prev = NULL;
error->next = ctx->errors;
while (error->next != NULL)
Feb 3, 2009
Feb 3, 2009
153
154
155
156
157
158
159
160
prev = error->next;
error->next = error->next->next;
} // while
if (prev != NULL)
prev->next = error;
else
ctx->errors = error;
Feb 3, 2009
Feb 3, 2009
162
163
ctx->error_count++;
} // else
164
165
} // failf
Feb 3, 2009
Feb 3, 2009
166
static inline void fail(Context *ctx, const char *reason)
Feb 3, 2009
Feb 3, 2009
168
failf(ctx, "%s", reason);
169
170
171
172
} // fail
static inline int isfail(const Context *ctx)
{
Feb 3, 2009
Feb 3, 2009
173
return ctx->isfail;
174
175
176
} // isfail
Dec 13, 2008
Dec 13, 2008
177
178
179
180
181
182
static inline int tokeq(const TokenizerContext *tctx, const char *token)
{
return (strcasecmp(tctx->token, token) == 0);
} // tokeq
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 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
Dec 10, 2008
Dec 10, 2008
207
208
209
210
211
212
213
214
215
static int ui32fromstr(const char *str, uint32 *ui32)
{
//*ui32 = (uint32) atoi(minstr);
char *endptr = NULL;
const long val = strtol(str, &endptr, 10);
*ui32 = (uint32) val;
return ((val >= 0) && (*str != '\0') && (*endptr == '\0'));
} // ui32fromstr
Feb 3, 2009
Feb 3, 2009
217
218
219
220
221
222
223
static inline void add_token_sourcepos(Context *ctx, const size_t idx)
{
ctx->token_to_source[idx].line = ctx->tctx.linenum;
ctx->token_to_source[idx].filename = NULL;
} // add_token_sourcepos
224
225
226
227
228
static void output_token_noswap(Context *ctx, const uint32 token)
{
if (isfail(ctx))
return;
Dec 8, 2008
Dec 8, 2008
229
230
231
232
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;
Dec 10, 2008
Dec 10, 2008
233
234
235
void *ptr;
ptr = Malloc(ctx, newsize * sizeof (uint32));
Dec 8, 2008
Dec 8, 2008
236
237
238
239
240
241
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;
Dec 10, 2008
Dec 10, 2008
242
Feb 3, 2009
Feb 3, 2009
243
ptr = Malloc(ctx, newsize * sizeof (SourcePos));
Dec 10, 2008
Dec 10, 2008
244
245
246
if (ptr == NULL)
return;
if (ctx->output_len > 0)
Feb 3, 2009
Feb 3, 2009
247
248
249
memcpy(ptr, ctx->token_to_source, ctx->output_len * sizeof (SourcePos));
Free(ctx, ctx->token_to_source);
ctx->token_to_source = (SourcePos *) ptr;
Dec 10, 2008
Dec 10, 2008
250
251
ctx->output_allocation = newsize;
Dec 8, 2008
Dec 8, 2008
252
253
} // if
Dec 10, 2008
Dec 10, 2008
254
ctx->output[ctx->output_len] = token;
Feb 3, 2009
Feb 3, 2009
255
add_token_sourcepos(ctx, ctx->output_len);
Dec 10, 2008
Dec 10, 2008
256
ctx->output_len++;
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
} // 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
Dec 13, 2008
Dec 13, 2008
298
static int tokenize_ctx(Context *ctx, TokenizerContext *tctx)
299
300
301
{
int idx = 0;
Dec 13, 2008
Dec 13, 2008
302
if (tctx->pushedback)
Dec 13, 2008
Dec 13, 2008
304
tctx->pushedback = 0;
Feb 3, 2009
Feb 3, 2009
305
return 1;
306
307
} // if
Dec 13, 2008
Dec 13, 2008
308
if (tctx->on_endline)
Dec 8, 2008
Dec 8, 2008
309
{
Dec 13, 2008
Dec 13, 2008
310
311
tctx->on_endline = 0;
tctx->linenum++; // passed a newline, update.
Dec 8, 2008
Dec 8, 2008
312
313
} // if
314
315
while (1)
{
Dec 10, 2008
Dec 10, 2008
316
// !!! FIXME: carefully crafted (but legal) comments can trigger this.
Dec 13, 2008
Dec 13, 2008
317
if (idx >= sizeof (tctx->token))
Feb 3, 2009
Feb 3, 2009
318
319
320
321
{
fail(ctx, "buffer overflow");
return 0;
} // if
Dec 13, 2008
Dec 13, 2008
323
char ch = *tctx->source;
324
325
326
327
if (ch == '\t')
ch = ' '; // collapse tabs into single spaces.
else if (ch == '\r')
{
Dec 13, 2008
Dec 13, 2008
328
if (tctx->source[1] == '\n')
329
330
331
332
continue; // ignore '\r' if this is "\r\n" ...
ch = '\n';
} // else if
Dec 10, 2008
Dec 10, 2008
333
if ((ch >= '0') && (ch <= '9'))
334
335
{
// starting a number, but rest of current token was not number.
Dec 13, 2008
Dec 13, 2008
336
if ((idx > 0) && ((tctx->prevchar < '0') || (tctx->prevchar > '9')))
Dec 13, 2008
Dec 13, 2008
338
tctx->token[idx++] = '\0';
Feb 3, 2009
Feb 3, 2009
339
return 1;
340
341
342
343
344
} // if
} // if
else
{
// starting a non-number, but rest of current token was numbers.
Dec 13, 2008
Dec 13, 2008
345
if ((idx > 0) && ((tctx->prevchar >= '0') && (tctx->prevchar <= '9')))
Dec 13, 2008
Dec 13, 2008
347
tctx->token[idx++] = '\0';
Feb 3, 2009
Feb 3, 2009
348
return 1;
349
350
351
352
353
354
355
356
} // if
} // else
switch (ch)
{
case '/':
case ';': // !!! FIXME: comment, right?
if (idx != 0) // finish off existing token.
Dec 13, 2008
Dec 13, 2008
357
tctx->token[idx] = '\0';
358
359
else
{
Dec 13, 2008
Dec 13, 2008
360
361
362
tctx->token[idx++] = ch;
tctx->source++;
if ((ch == '/') && (*tctx->source == '/'))
Dec 13, 2008
Dec 13, 2008
364
365
tctx->token[idx++] = '/';
tctx->source++;
Dec 13, 2008
Dec 13, 2008
367
tctx->token[idx++] = '\0';
368
} // else
Feb 3, 2009
Feb 3, 2009
369
return 1;
370
371
case ' ':
Dec 13, 2008
Dec 13, 2008
372
if (tctx->prevchar == ' ')
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
break; // multiple whitespace collapses into one.
// intentional fall-through...
case '_':
case '[':
case ']':
case '(':
case ')':
case '!':
case '+':
case '-':
case ',':
case '.':
case '\n':
if (idx != 0) // finish off existing token.
Dec 13, 2008
Dec 13, 2008
388
tctx->token[idx] = '\0';
389
390
391
else // this is a token in itself.
{
if (ch == '\n')
Dec 13, 2008
Dec 13, 2008
392
393
394
395
tctx->on_endline = 1;
tctx->source++;
tctx->token[idx++] = ch;
tctx->token[idx++] = '\0';
396
} // else
Feb 3, 2009
Feb 3, 2009
397
return 1;
398
399
case '\0':
Dec 13, 2008
Dec 13, 2008
400
tctx->token[idx] = '\0';
401
if (idx != 0) // had any chars? It's a token.
Feb 3, 2009
Feb 3, 2009
402
403
404
return 1;
ctx->eof = 1;
return 0;
405
406
default:
Dec 13, 2008
Dec 13, 2008
407
408
tctx->source++;
tctx->token[idx++] = ch;
409
410
411
break;
} // switch
Dec 13, 2008
Dec 13, 2008
412
tctx->prevchar = ch;
413
414
} // while
Feb 3, 2009
Feb 3, 2009
415
416
assert(0 && "Shouldn't hit this code");
return 0;
Dec 13, 2008
Dec 13, 2008
417
} // tokenize_ctx
418
419
420
421
static inline int tokenize(Context *ctx)
{
Dec 13, 2008
Dec 13, 2008
422
423
const int rc = tokenize_ctx(ctx, &ctx->tctx);
424
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
425
printf("TOKENIZE: %d '%s'\n", rc,
Dec 13, 2008
Dec 13, 2008
426
(ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token);
Dec 13, 2008
Dec 13, 2008
428
429
430
431
432
return rc;
} // tokenize
Feb 3, 2009
Feb 3, 2009
433
static void pushback_ctx(Context *ctx, TokenizerContext *tctx)
Feb 3, 2009
Feb 3, 2009
435
436
437
assert(!tctx->pushedback);
tctx->pushedback = 1;
} // pushback_ctx
Dec 10, 2008
Dec 10, 2008
438
Dec 13, 2008
Dec 13, 2008
439
Feb 3, 2009
Feb 3, 2009
440
static inline void pushback(Context *ctx)
Dec 13, 2008
Dec 13, 2008
441
{
Feb 3, 2009
Feb 3, 2009
442
pushback_ctx(ctx, &ctx->tctx);
Dec 13, 2008
Dec 13, 2008
443
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
444
printf("PUSHBACK\n");
Dec 13, 2008
Dec 13, 2008
445
#endif
446
447
448
} // pushback
Dec 13, 2008
Dec 13, 2008
449
450
451
static int nexttoken_ctx(Context *ctx, TokenizerContext *tctx,
const int ignoreeol, const int ignorewhitespace,
const int eolok, const int eosok)
Feb 3, 2009
Feb 3, 2009
453
while (tokenize_ctx(ctx, tctx))
Dec 13, 2008
Dec 13, 2008
455
if (tokeq(tctx, "\n"))
456
457
458
459
{
if (ignoreeol)
continue;
else if (!eolok)
Feb 3, 2009
Feb 3, 2009
460
461
462
463
{
fail(ctx, "Unexpected EOL");
return 0;
} // else if
464
465
} // if
Dec 13, 2008
Dec 13, 2008
466
else if (tokeq(tctx, " "))
467
468
469
470
471
472
{
if (ignorewhitespace)
continue;
} // else if
// skip comments...
Dec 13, 2008
Dec 13, 2008
473
else if (tokeq(tctx, "//") || tokeq(tctx, ";"))
Feb 3, 2009
Feb 3, 2009
475
while (tokenize_ctx(ctx, tctx))
Dec 13, 2008
Dec 13, 2008
477
if (tokeq(tctx, "\n"))
Dec 10, 2008
Dec 10, 2008
478
{
Dec 13, 2008
Dec 13, 2008
479
pushback_ctx(ctx, tctx);
Dec 10, 2008
Dec 10, 2008
481
} // if
482
} // while
Dec 10, 2008
Dec 10, 2008
483
continue; // pick up from newline, go again.
484
485
486
487
488
} // if
break;
} // while
Feb 3, 2009
Feb 3, 2009
489
490
491
492
493
if ((ctx->eof) && (!eosok))
{
fail(ctx, "Unexpected EOF");
return 0;
} // if
Dec 13, 2008
Dec 13, 2008
494
Feb 3, 2009
Feb 3, 2009
495
return 1;
Dec 13, 2008
Dec 13, 2008
496
497
498
499
500
501
502
503
504
505
} // nexttoken_ctx
static inline int nexttoken(Context *ctx, const int ignoreeol,
const int ignorewhitespace, const int eolok,
const int eosok)
{
const int rc = nexttoken_ctx(ctx, &ctx->tctx, ignoreeol,
ignorewhitespace, eolok, eosok);
506
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
507
printf("NEXTTOKEN: %d '%s'\n", rc,
Dec 13, 2008
Dec 13, 2008
508
(ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token);
509
510
511
512
513
514
#endif
return rc;
} // nexttoken
Feb 3, 2009
Feb 3, 2009
515
516
517
518
519
520
521
522
523
524
525
526
527
528
static void skip_line(Context *ctx)
{
if (!tokeq(&ctx->tctx, "\n"))
{
while (nexttoken(ctx, 0, 1, 1, 1))
{
if (tokeq(&ctx->tctx, "\n"))
break;
} // while
} // if
} // skip_line
static void require_endline(Context *ctx)
Dec 13, 2008
Dec 13, 2008
530
TokenizerContext *tctx = &ctx->tctx;
531
const int rc = nexttoken(ctx, 0, 1, 1, 1);
Feb 3, 2009
Feb 3, 2009
532
533
534
535
536
537
538
if (ctx->eof)
return; // we'll call this an EOL.
else if ((rc == 0) || (!tokeq(tctx, "\n")))
{
fail(ctx, "Endline expected");
skip_line(ctx);
} // else if
539
540
541
} // require_endline
Dec 8, 2008
Dec 8, 2008
542
static int require_comma(Context *ctx)
Dec 13, 2008
Dec 13, 2008
544
TokenizerContext *tctx = &ctx->tctx;
Dec 8, 2008
Dec 8, 2008
545
const int rc = nexttoken(ctx, 0, 1, 0, 0);
Feb 3, 2009
Feb 3, 2009
546
547
548
549
550
551
if ((rc == 0) || (!tokeq(tctx, ",")))
{
fail(ctx, "Comma expected");
return 0;
} // if
return 1;
Dec 8, 2008
Dec 8, 2008
552
} // require_comma
553
554
555
556
static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum)
{
Dec 13, 2008
Dec 13, 2008
557
TokenizerContext *tctx = &ctx->tctx;
Feb 3, 2009
Feb 3, 2009
558
559
if (!nexttoken(ctx, 0, 1, 0, 0))
return 0;
560
561
562
563
int neednum = 1;
int regnum = 0;
RegisterType regtype = REG_TYPE_TEMP;
Dec 13, 2008
Dec 13, 2008
564
if (tokeq(tctx, "r"))
565
regtype = REG_TYPE_TEMP;
Dec 13, 2008
Dec 13, 2008
566
else if (tokeq(tctx, "v"))
567
regtype = REG_TYPE_INPUT;
Dec 13, 2008
Dec 13, 2008
568
else if (tokeq(tctx, "c"))
569
regtype = REG_TYPE_CONST;
Dec 13, 2008
Dec 13, 2008
570
else if (tokeq(tctx, "i"))
571
regtype = REG_TYPE_CONSTINT;
Dec 13, 2008
Dec 13, 2008
572
else if (tokeq(tctx, "b"))
573
regtype = REG_TYPE_CONSTBOOL;
Dec 13, 2008
Dec 13, 2008
574
else if (tokeq(tctx, "oC"))
575
regtype = REG_TYPE_COLOROUT;
Dec 13, 2008
Dec 13, 2008
576
else if (tokeq(tctx, "s"))
577
regtype = REG_TYPE_SAMPLER;
Dec 13, 2008
Dec 13, 2008
578
else if (tokeq(tctx, "oD"))
579
regtype = REG_TYPE_ATTROUT;
Dec 13, 2008
Dec 13, 2008
580
else if (tokeq(tctx, "l"))
581
regtype = REG_TYPE_LABEL;
Dec 13, 2008
Dec 13, 2008
582
else if (tokeq(tctx, "p"))
583
regtype = REG_TYPE_PREDICATE;
Dec 13, 2008
Dec 13, 2008
584
else if (tokeq(tctx, "oDepth"))
Dec 13, 2008
Dec 13, 2008
585
586
587
588
{
regtype = REG_TYPE_DEPTHOUT;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
589
else if (tokeq(tctx, "aL"))
590
591
592
593
{
regtype = REG_TYPE_LOOP;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
594
else if (tokeq(tctx, "o"))
595
596
{
if (!shader_is_vertex(ctx) || !shader_version_atleast(ctx, 3, 0))
Feb 3, 2009
Feb 3, 2009
597
fail(ctx, "Output register not valid in this shader type");
598
599
regtype = REG_TYPE_OUTPUT;
} // else if
Dec 13, 2008
Dec 13, 2008
600
else if (tokeq(tctx, "oT"))
Dec 12, 2008
Dec 12, 2008
602
if (shader_is_vertex(ctx) && shader_version_atleast(ctx, 3, 0))
Feb 3, 2009
Feb 3, 2009
603
fail(ctx, "Output register not valid in this shader type");
604
605
regtype = REG_TYPE_OUTPUT;
} // else if
Dec 13, 2008
Dec 13, 2008
606
else if (tokeq(tctx, "a"))
607
608
{
if (!shader_is_vertex(ctx))
Feb 3, 2009
Feb 3, 2009
609
fail(ctx, "Address register only valid in vertex shaders.");
610
611
regtype = REG_TYPE_ADDRESS;
} // else if
Dec 13, 2008
Dec 13, 2008
612
else if (tokeq(tctx, "t"))
613
614
{
if (!shader_is_pixel(ctx))
Feb 3, 2009
Feb 3, 2009
615
fail(ctx, "Address register only valid in pixel shaders.");
616
617
regtype = REG_TYPE_ADDRESS;
} // else if
Dec 13, 2008
Dec 13, 2008
618
else if (tokeq(tctx, "vPos"))
619
620
621
622
623
{
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_POSITION;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
624
else if (tokeq(tctx, "vFace"))
625
626
627
628
629
{
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_FACE;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
630
else if (tokeq(tctx, "oPos"))
631
632
633
634
635
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_POSITION;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
636
else if (tokeq(tctx, "oFog"))
637
638
639
640
641
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_FOG;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
642
else if (tokeq(tctx, "oPts"))
643
644
645
646
647
648
649
650
651
652
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_POINT_SIZE;
neednum = 0;
} // else if
//case REG_TYPE_TEMPFLOAT16: // !!! FIXME: don't know this asm string
else
{
Feb 3, 2009
Feb 3, 2009
653
654
655
656
fail(ctx, "expected register type");
regtype = REG_TYPE_CONST;
regnum = 0;
neednum = 0;
657
658
} // else
Dec 10, 2008
Dec 10, 2008
659
660
if (neednum)
{
Dec 13, 2008
Dec 13, 2008
661
662
663
664
665
// Make a temp TokenizerContext, since we need to skip whitespace here,
// but if the next non-whitespace token isn't '[', we'll want to get
// that whitespace back.
TokenizerContext tmptctx;
memcpy(&tmptctx, tctx, sizeof (TokenizerContext));
Feb 3, 2009
Feb 3, 2009
666
667
if (!nexttoken_ctx(ctx, &tmptctx, 0, 1, 1, 1))
return 0;
Dec 14, 2008
Dec 14, 2008
668
else if (tokeq(&tmptctx, "["))
Dec 10, 2008
Dec 10, 2008
669
670
671
neednum = 0;
} // if
672
673
if (neednum)
{
Feb 3, 2009
Feb 3, 2009
674
675
if (!nexttoken(ctx, 0, 0, 0, 0))
return 0;
Dec 10, 2008
Dec 10, 2008
677
uint32 ui32 = 0;
Dec 13, 2008
Dec 13, 2008
678
if (!ui32fromstr(tctx->token, &ui32))
Feb 3, 2009
Feb 3, 2009
679
fail(ctx, "Invalid register index");
Dec 10, 2008
Dec 10, 2008
680
regnum = (int) ui32;
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
} // 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
{
Feb 3, 2009
Feb 3, 2009
708
fail(ctx, "Invalid const register index");
709
710
711
712
713
714
} // else
} // if
*rtype = regtype;
*rnum = regnum;
Feb 3, 2009
Feb 3, 2009
715
return 1;
716
717
718
} // parse_register_name
Feb 3, 2009
Feb 3, 2009
719
static void set_result_shift(Context *ctx, DestArgInfo *info, const int val)
Dec 8, 2008
Dec 8, 2008
721
if (info->result_shift != 0)
Feb 3, 2009
Feb 3, 2009
722
fail(ctx, "Multiple result shift modifiers");
Dec 8, 2008
Dec 8, 2008
723
724
info->result_shift = val;
} // set_result_shift
Dec 8, 2008
Dec 8, 2008
726
Dec 13, 2008
Dec 13, 2008
727
static int parse_destination_token(Context *ctx)
Dec 8, 2008
Dec 8, 2008
728
{
Dec 13, 2008
Dec 13, 2008
729
730
731
TokenizerContext *tctx = &ctx->tctx;
DestArgInfo *info = &ctx->dest_arg;
Dec 12, 2008
Dec 12, 2008
732
memset(info, '\0', sizeof (DestArgInfo));
733
734
735
736
// See if there are destination modifiers on the instruction itself...
while (1)
{
Feb 3, 2009
Feb 3, 2009
737
738
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
739
else if (tokeq(tctx, " "))
740
break; // done with modifiers.
Dec 13, 2008
Dec 13, 2008
741
else if (!tokeq(tctx, "_"))
Feb 3, 2009
Feb 3, 2009
742
743
744
fail(ctx, "Expected modifier or whitespace");
else if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 12, 2008
Dec 12, 2008
745
// !!! FIXME: this can be cleaned up when tokenizer is fixed.
Dec 13, 2008
Dec 13, 2008
746
else if (tokeq(tctx, "x"))
Dec 12, 2008
Dec 12, 2008
747
{
Feb 3, 2009
Feb 3, 2009
748
749
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
750
else if (tokeq(tctx, "2"))
Dec 12, 2008
Dec 12, 2008
751
set_result_shift(ctx, info, 0x1);
Dec 13, 2008
Dec 13, 2008
752
else if (tokeq(tctx, "4"))
Dec 12, 2008
Dec 12, 2008
753
set_result_shift(ctx, info, 0x2);
Dec 13, 2008
Dec 13, 2008
754
else if (tokeq(tctx, "8"))
Dec 12, 2008
Dec 12, 2008
755
756
set_result_shift(ctx, info, 0x3);
else
Feb 3, 2009
Feb 3, 2009
757
fail(ctx, "Expected modifier");
Dec 12, 2008
Dec 12, 2008
758
759
} // else if
// !!! FIXME: this can be cleaned up when tokenizer is fixed.
Dec 13, 2008
Dec 13, 2008
760
else if (tokeq(tctx, "d"))
Dec 12, 2008
Dec 12, 2008
761
{
Feb 3, 2009
Feb 3, 2009
762
763
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
764
else if (tokeq(tctx, "8"))
Dec 12, 2008
Dec 12, 2008
765
set_result_shift(ctx, info, 0xD);
Dec 13, 2008
Dec 13, 2008
766
else if (tokeq(tctx, "4"))
Dec 12, 2008
Dec 12, 2008
767
set_result_shift(ctx, info, 0xE);
Dec 13, 2008
Dec 13, 2008
768
else if (tokeq(tctx, "2"))
Dec 12, 2008
Dec 12, 2008
769
770
set_result_shift(ctx, info, 0xF);
else
Feb 3, 2009
Feb 3, 2009
771
fail(ctx, "Expected modifier");
Dec 12, 2008
Dec 12, 2008
772
} // else if
Dec 13, 2008
Dec 13, 2008
773
else if (tokeq(tctx, "sat"))
774
info->result_mod |= MOD_SATURATE;
Dec 13, 2008
Dec 13, 2008
775
else if (tokeq(tctx, "pp"))
776
info->result_mod |= MOD_PP;
Dec 13, 2008
Dec 13, 2008
777
else if (tokeq(tctx, "centroid"))
778
779
info->result_mod |= MOD_CENTROID;
else
Feb 3, 2009
Feb 3, 2009
780
fail(ctx, "Expected modifier");
781
782
} // while
Feb 3, 2009
Feb 3, 2009
783
784
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
785
786
// !!! FIXME: predicates.
Dec 13, 2008
Dec 13, 2008
787
if (tokeq(tctx, "("))
Feb 3, 2009
Feb 3, 2009
788
789
fail(ctx, "Predicates unsupported at this time"); // !!! FIXME: ...
790
791
pushback(ctx); // parse_register_name calls nexttoken().
Feb 3, 2009
Feb 3, 2009
792
parse_register_name(ctx, &info->regtype, &info->regnum);
Feb 3, 2009
Feb 3, 2009
794
795
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
796
797
798
// !!! FIXME: can dest registers do relative addressing?
Feb 3, 2009
Feb 3, 2009
799
int invalid_writemask = 0;
Dec 14, 2008
Dec 14, 2008
800
int implicit_writemask = 0;
Dec 13, 2008
Dec 13, 2008
801
if (!tokeq(tctx, "."))
Dec 14, 2008
Dec 14, 2008
803
implicit_writemask = 1;
804
805
806
807
info->writemask = 0xF;
info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 1;
pushback(ctx); // no explicit writemask; do full mask.
} // if
Dec 14, 2008
Dec 14, 2008
808
809
810
// !!! 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) )
Feb 3, 2009
Feb 3, 2009
811
812
813
fail(ctx, "Writemask specified for scalar register");
else if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
814
else if (tokeq(tctx, ""))
Feb 3, 2009
Feb 3, 2009
815
invalid_writemask = 1;
816
817
else
{
Dec 13, 2008
Dec 13, 2008
818
char *ptr = tctx->token;
819
info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 0;
Dec 8, 2008
Dec 8, 2008
820
821
822
823
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++; }
Dec 13, 2008
Dec 13, 2008
824
if ((ptr == tctx->token) && (shader_is_pixel(ctx)))
Dec 8, 2008
Dec 8, 2008
826
827
828
829
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++; }
830
831
832
} // if
if (*ptr != '\0')
Feb 3, 2009
Feb 3, 2009
833
invalid_writemask = 1;
834
835
836
837
838
839
840
info->writemask = ( ((info->writemask0 & 0x1) << 0) |
((info->writemask1 & 0x1) << 1) |
((info->writemask2 & 0x1) << 2) |
((info->writemask3 & 0x1) << 3) );
} // else
Feb 3, 2009
Feb 3, 2009
841
842
843
if (invalid_writemask)
fail(ctx, "Invalid writemask");
Dec 14, 2008
Dec 14, 2008
844
845
846
847
848
// !!! 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) )
Feb 3, 2009
Feb 3, 2009
849
fail(ctx, "Writemask specified for scalar register");
Dec 14, 2008
Dec 14, 2008
850
851
} // if
852
853
854
info->orig_writemask = info->writemask;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
Feb 3, 2009
Feb 3, 2009
855
856
857
858
{
fail(ctx, "Too many tokens");
return 1;
} // if
859
860
ctx->tokenbuf[ctx->tokenbufpos++] =
Dec 8, 2008
Dec 8, 2008
861
( ((((uint32) 1)) << 31) |
862
863
864
865
((((uint32) info->regnum) & 0x7ff) << 0) |
((((uint32) info->relative) & 0x1) << 13) |
((((uint32) info->result_mod) & 0xF) << 20) |
((((uint32) info->result_shift) & 0xF) << 24) |
Dec 11, 2008
Dec 11, 2008
866
((((uint32) info->writemask) & 0xF) << 16) |
867
868
869
870
871
872
873
((((uint32) info->regtype) & 0x7) << 28) |
((((uint32) info->regtype) & 0x18) << 8) );
return 1;
} // parse_destination_token
Dec 10, 2008
Dec 10, 2008
874
875
876
static void set_source_mod(Context *ctx, const int negate,
const SourceMod norm, const SourceMod negated,
SourceMod *srcmod)
Dec 8, 2008
Dec 8, 2008
878
879
880
881
882
if ( (*srcmod != SRCMOD_NONE) || (negate && (negated == SRCMOD_NONE)) )
fail(ctx, "Incompatible source modifiers");
else
*srcmod = ((negate) ? negated : norm);
} // set_source_mod
Dec 8, 2008
Dec 8, 2008
885
static int parse_source_token_maybe_relative(Context *ctx, const int relok)
Dec 13, 2008
Dec 13, 2008
887
TokenizerContext *tctx = &ctx->tctx;
Dec 8, 2008
Dec 8, 2008
888
889
890
int retval = 1;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
Feb 3, 2009
Feb 3, 2009
891
892
893
894
{
fail(ctx, "Too many tokens");
return 0;
} // if
Dec 8, 2008
Dec 8, 2008
895
896
897
// mark this now, so optional relative addressing token is placed second.
uint32 *token = &ctx->tokenbuf[ctx->tokenbufpos++];
Feb 3, 2009
Feb 3, 2009
898
*token = 0;
Dec 8, 2008
Dec 8, 2008
899
900
901
SourceMod srcmod = SRCMOD_NONE;
int negate = 0;
Feb 3, 2009
Feb 3, 2009
902
903
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
904
else if (tokeq(tctx, "1"))
Dec 8, 2008
Dec 8, 2008
905
{
Feb 3, 2009
Feb 3, 2009
906
907
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
908
else if (!tokeq(tctx, "-"))
Feb 3, 2009
Feb 3, 2009
909
fail(ctx, "Unexpected value");
Dec 8, 2008
Dec 8, 2008
910
911
912
else
srcmod = SRCMOD_COMPLEMENT;
} // else
Dec 13, 2008
Dec 13, 2008
913
else if (tokeq(tctx, "!"))
Dec 8, 2008
Dec 8, 2008
914
srcmod = SRCMOD_NOT;
Dec 13, 2008
Dec 13, 2008
915
else if (tokeq(tctx, "-"))
Dec 8, 2008
Dec 8, 2008
916
917
918
negate = 1;
else
pushback(ctx);
Dec 8, 2008
Dec 8, 2008
920
921
RegisterType regtype;
int regnum;
Feb 3, 2009
Feb 3, 2009
922
923
924
parse_register_name(ctx, &regtype, &regnum);
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
Dec 13, 2008
Dec 13, 2008
925
else if (!tokeq(tctx, "_"))
Dec 8, 2008
Dec 8, 2008
926
pushback(ctx);
Feb 3, 2009
Feb 3, 2009
927
928
else if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
929
else if (tokeq(tctx, "bias"))
Dec 10, 2008
Dec 10, 2008
930
set_source_mod(ctx, negate, SRCMOD_BIAS, SRCMOD_BIASNEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
931
else if (tokeq(tctx, "bx2"))
Dec 10, 2008
Dec 10, 2008
932
set_source_mod(ctx, negate, SRCMOD_SIGN, SRCMOD_SIGNNEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
933
else if (tokeq(tctx, "x2"))
Dec 10, 2008
Dec 10, 2008
934
set_source_mod(ctx, negate, SRCMOD_X2, SRCMOD_X2NEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
935
else if (tokeq(tctx, "dz"))
Dec 10, 2008
Dec 10, 2008
936
set_source_mod(ctx, negate, SRCMOD_DZ, SRCMOD_NONE, &srcmod);
Dec 13, 2008
Dec 13, 2008
937
else if (tokeq(tctx, "dw"))
Dec 10, 2008
Dec 10, 2008
938
set_source_mod(ctx, negate, SRCMOD_DW, SRCMOD_NONE, &srcmod);
Dec 13, 2008
Dec 13, 2008
939
else if (tokeq(tctx, "abs"))
Dec 10, 2008
Dec 10, 2008
940
set_source_mod(ctx, negate, SRCMOD_ABS, SRCMOD_ABSNEGATE, &srcmod);
Dec 8, 2008
Dec 8, 2008
941
else
Feb 3, 2009
Feb 3, 2009
942
fail(ctx, "Invalid source modifier");
Feb 3, 2009
Feb 3, 2009
944
945
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
Dec 8, 2008
Dec 8, 2008
947
uint32 relative = 0;
Dec 13, 2008
Dec 13, 2008
948
if (!tokeq(tctx, "["))
Dec 8, 2008
Dec 8, 2008
949
950
951
pushback(ctx); // not relative addressing?
else
{
Feb 3, 2009
Feb 3, 2009
952
953
954
955
956
957
if (!relok)
fail(ctx, "Relative addressing not permitted here.");
else
retval++;
parse_source_token_maybe_relative(ctx, 0);
Dec 8, 2008
Dec 8, 2008
958
relative = 1;
Feb 3, 2009
Feb 3, 2009
959
960
if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
961
else if (!tokeq(tctx, "+"))
Dec 10, 2008
Dec 10, 2008
962
pushback(ctx);
Feb 3, 2009
Feb 3, 2009
963
964
else if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 10, 2008
Dec 10, 2008
965
966
967
968
969
else
{
if (regnum != 0) // !!! FIXME: maybe c3[a0.x + 5] is legal and becomes c[a0.x + 8] ?
fail(ctx, "Relative addressing with explicit register number.");
uint32 ui32 = 0;
Dec 13, 2008
Dec 13, 2008
970
if (!ui32fromstr(tctx->token, &ui32))
Feb 3, 2009
Feb 3, 2009
971
fail(ctx, "Invalid relative addressing offset");
Dec 10, 2008
Dec 10, 2008
972
973
974
regnum += (int) ui32;
} // else
Feb 3, 2009
Feb 3, 2009
975
976
if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
977
else if (!tokeq(tctx, "]"))
Feb 3, 2009
Feb 3, 2009
978
fail(ctx, "Expected ']'");
Dec 8, 2008
Dec 8, 2008
979
} // else
Feb 3, 2009
Feb 3, 2009
981
982
if (!nexttoken(ctx, 0, 1, 1, 1))
return retval;
Dec 8, 2008
Dec 8, 2008
983
Feb 3, 2009
Feb 3, 2009
984
int invalid_swizzle = 0;
Dec 8, 2008
Dec 8, 2008
985
uint32 swizzle = 0;
Dec 13, 2008
Dec 13, 2008
986
if (!tokeq(tctx, "."))
Dec 8, 2008
Dec 8, 2008
987
988
989
990
{
swizzle = 0xE4; // 0xE4 == 11100100 ... 0 1 2 3. No swizzle.
pushback(ctx); // no explicit writemask; do full mask.
} // if
Dec 10, 2008
Dec 10, 2008
991
else if (scalar_register(ctx->shader_type, regtype, regnum))
Feb 3, 2009
Feb 3, 2009
992
993
994
fail(ctx, "Swizzle specified for scalar register");
else if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
995
else if (tokeq(tctx, ""))
Feb 3, 2009
Feb 3, 2009
996
invalid_swizzle = 1;
Dec 8, 2008
Dec 8, 2008
997
998
999
else
{
// deal with shortened form (.x = .xxxx, etc).
Dec 13, 2008
Dec 13, 2008
1000
if (tctx->token[1] == '\0')