Skip to content

Latest commit

 

History

History
2084 lines (1766 loc) · 58.3 KB

mojoshader_assembler.c

File metadata and controls

2084 lines (1766 loc) · 58.3 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
const char *fname = NULL;
unsigned int linenum = 0;
int error_position = 0;
Feb 3, 2009
Feb 3, 2009
103
104
ctx->isfail = 1;
Feb 3, 2009
Feb 3, 2009
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
140
141
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
142
143
{
va_start(ap, fmt);
Feb 3, 2009
Feb 3, 2009
144
vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
145
146
va_end(ap);
Feb 3, 2009
Feb 3, 2009
147
148
149
error->error.error = failstr;
error->error.filename = fname ? StrDup(ctx, fname) : NULL;
error->error.error_position = error_position;
Feb 3, 2009
Feb 3, 2009
150
error->next = NULL;
Feb 3, 2009
Feb 3, 2009
151
152
ErrorList *prev = NULL;
Feb 3, 2009
Feb 3, 2009
153
154
ErrorList *item = ctx->errors;
while (item != NULL)
Feb 3, 2009
Feb 3, 2009
156
157
prev = item;
item = error->next;
Feb 3, 2009
Feb 3, 2009
158
159
} // while
Feb 3, 2009
Feb 3, 2009
160
if (prev == NULL)
Feb 3, 2009
Feb 3, 2009
161
ctx->errors = error;
Feb 3, 2009
Feb 3, 2009
162
163
else
prev->next = error;
Feb 3, 2009
Feb 3, 2009
165
166
ctx->error_count++;
} // else
167
168
} // failf
Feb 3, 2009
Feb 3, 2009
169
static inline void fail(Context *ctx, const char *reason)
Feb 3, 2009
Feb 3, 2009
171
failf(ctx, "%s", reason);
172
173
174
175
} // fail
static inline int isfail(const Context *ctx)
{
Feb 3, 2009
Feb 3, 2009
176
return ctx->isfail;
177
178
179
} // isfail
Dec 13, 2008
Dec 13, 2008
180
181
182
183
184
185
static inline int tokeq(const TokenizerContext *tctx, const char *token)
{
return (strcasecmp(tctx->token, token) == 0);
} // tokeq
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// 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
210
211
212
213
214
215
216
217
218
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
220
221
222
223
224
225
226
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
227
228
229
230
231
static void output_token_noswap(Context *ctx, const uint32 token)
{
if (isfail(ctx))
return;
Dec 8, 2008
Dec 8, 2008
232
233
234
235
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
236
237
238
void *ptr;
ptr = Malloc(ctx, newsize * sizeof (uint32));
Dec 8, 2008
Dec 8, 2008
239
240
241
242
243
244
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
245
Feb 3, 2009
Feb 3, 2009
246
ptr = Malloc(ctx, newsize * sizeof (SourcePos));
Dec 10, 2008
Dec 10, 2008
247
248
249
if (ptr == NULL)
return;
if (ctx->output_len > 0)
Feb 3, 2009
Feb 3, 2009
250
251
252
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
253
254
ctx->output_allocation = newsize;
Dec 8, 2008
Dec 8, 2008
255
256
} // if
Dec 10, 2008
Dec 10, 2008
257
ctx->output[ctx->output_len] = token;
Feb 3, 2009
Feb 3, 2009
258
add_token_sourcepos(ctx, ctx->output_len);
Dec 10, 2008
Dec 10, 2008
259
ctx->output_len++;
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
298
299
300
} // 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
301
static int tokenize_ctx(Context *ctx, TokenizerContext *tctx)
302
303
304
{
int idx = 0;
Dec 13, 2008
Dec 13, 2008
305
if (tctx->pushedback)
Dec 13, 2008
Dec 13, 2008
307
tctx->pushedback = 0;
Feb 3, 2009
Feb 3, 2009
308
return 1;
309
310
} // if
Dec 13, 2008
Dec 13, 2008
311
if (tctx->on_endline)
Dec 8, 2008
Dec 8, 2008
312
{
Dec 13, 2008
Dec 13, 2008
313
314
tctx->on_endline = 0;
tctx->linenum++; // passed a newline, update.
Dec 8, 2008
Dec 8, 2008
315
316
} // if
317
318
while (1)
{
Dec 10, 2008
Dec 10, 2008
319
// !!! FIXME: carefully crafted (but legal) comments can trigger this.
Dec 13, 2008
Dec 13, 2008
320
if (idx >= sizeof (tctx->token))
Feb 3, 2009
Feb 3, 2009
321
322
323
324
{
fail(ctx, "buffer overflow");
return 0;
} // if
Dec 13, 2008
Dec 13, 2008
326
char ch = *tctx->source;
327
328
329
330
if (ch == '\t')
ch = ' '; // collapse tabs into single spaces.
else if (ch == '\r')
{
Dec 13, 2008
Dec 13, 2008
331
if (tctx->source[1] == '\n')
332
333
334
335
continue; // ignore '\r' if this is "\r\n" ...
ch = '\n';
} // else if
Dec 10, 2008
Dec 10, 2008
336
if ((ch >= '0') && (ch <= '9'))
337
338
{
// starting a number, but rest of current token was not number.
Dec 13, 2008
Dec 13, 2008
339
if ((idx > 0) && ((tctx->prevchar < '0') || (tctx->prevchar > '9')))
Dec 13, 2008
Dec 13, 2008
341
tctx->token[idx++] = '\0';
Feb 3, 2009
Feb 3, 2009
342
return 1;
343
344
345
346
347
} // if
} // if
else
{
// starting a non-number, but rest of current token was numbers.
Dec 13, 2008
Dec 13, 2008
348
if ((idx > 0) && ((tctx->prevchar >= '0') && (tctx->prevchar <= '9')))
Dec 13, 2008
Dec 13, 2008
350
tctx->token[idx++] = '\0';
Feb 3, 2009
Feb 3, 2009
351
return 1;
352
353
354
355
356
357
358
359
} // if
} // else
switch (ch)
{
case '/':
case ';': // !!! FIXME: comment, right?
if (idx != 0) // finish off existing token.
Dec 13, 2008
Dec 13, 2008
360
tctx->token[idx] = '\0';
361
362
else
{
Dec 13, 2008
Dec 13, 2008
363
364
365
tctx->token[idx++] = ch;
tctx->source++;
if ((ch == '/') && (*tctx->source == '/'))
Dec 13, 2008
Dec 13, 2008
367
368
tctx->token[idx++] = '/';
tctx->source++;
Dec 13, 2008
Dec 13, 2008
370
tctx->token[idx++] = '\0';
371
} // else
Feb 3, 2009
Feb 3, 2009
372
return 1;
373
374
case ' ':
Dec 13, 2008
Dec 13, 2008
375
if (tctx->prevchar == ' ')
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
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
391
tctx->token[idx] = '\0';
392
393
394
else // this is a token in itself.
{
if (ch == '\n')
Dec 13, 2008
Dec 13, 2008
395
396
397
398
tctx->on_endline = 1;
tctx->source++;
tctx->token[idx++] = ch;
tctx->token[idx++] = '\0';
399
} // else
Feb 3, 2009
Feb 3, 2009
400
return 1;
401
402
case '\0':
Dec 13, 2008
Dec 13, 2008
403
tctx->token[idx] = '\0';
404
if (idx != 0) // had any chars? It's a token.
Feb 3, 2009
Feb 3, 2009
405
406
407
return 1;
ctx->eof = 1;
return 0;
408
409
default:
Dec 13, 2008
Dec 13, 2008
410
411
tctx->source++;
tctx->token[idx++] = ch;
412
413
414
break;
} // switch
Dec 13, 2008
Dec 13, 2008
415
tctx->prevchar = ch;
416
417
} // while
Feb 3, 2009
Feb 3, 2009
418
419
assert(0 && "Shouldn't hit this code");
return 0;
Dec 13, 2008
Dec 13, 2008
420
} // tokenize_ctx
421
422
423
424
static inline int tokenize(Context *ctx)
{
Dec 13, 2008
Dec 13, 2008
425
426
const int rc = tokenize_ctx(ctx, &ctx->tctx);
427
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
428
printf("TOKENIZE: %d '%s'\n", rc,
Dec 13, 2008
Dec 13, 2008
429
(ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token);
Dec 13, 2008
Dec 13, 2008
431
432
433
434
435
return rc;
} // tokenize
Feb 3, 2009
Feb 3, 2009
436
static void pushback_ctx(Context *ctx, TokenizerContext *tctx)
Feb 3, 2009
Feb 3, 2009
438
439
440
assert(!tctx->pushedback);
tctx->pushedback = 1;
} // pushback_ctx
Dec 10, 2008
Dec 10, 2008
441
Dec 13, 2008
Dec 13, 2008
442
Feb 3, 2009
Feb 3, 2009
443
static inline void pushback(Context *ctx)
Dec 13, 2008
Dec 13, 2008
444
{
Feb 3, 2009
Feb 3, 2009
445
pushback_ctx(ctx, &ctx->tctx);
Dec 13, 2008
Dec 13, 2008
446
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
447
printf("PUSHBACK\n");
Dec 13, 2008
Dec 13, 2008
448
#endif
449
450
451
} // pushback
Dec 13, 2008
Dec 13, 2008
452
453
454
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
456
while (tokenize_ctx(ctx, tctx))
Dec 13, 2008
Dec 13, 2008
458
if (tokeq(tctx, "\n"))
459
460
461
462
{
if (ignoreeol)
continue;
else if (!eolok)
Feb 3, 2009
Feb 3, 2009
463
464
465
466
{
fail(ctx, "Unexpected EOL");
return 0;
} // else if
467
468
} // if
Dec 13, 2008
Dec 13, 2008
469
else if (tokeq(tctx, " "))
470
471
472
473
474
475
{
if (ignorewhitespace)
continue;
} // else if
// skip comments...
Dec 13, 2008
Dec 13, 2008
476
else if (tokeq(tctx, "//") || tokeq(tctx, ";"))
Feb 3, 2009
Feb 3, 2009
478
while (tokenize_ctx(ctx, tctx))
Dec 13, 2008
Dec 13, 2008
480
if (tokeq(tctx, "\n"))
Dec 10, 2008
Dec 10, 2008
481
{
Dec 13, 2008
Dec 13, 2008
482
pushback_ctx(ctx, tctx);
Dec 10, 2008
Dec 10, 2008
484
} // if
485
} // while
Dec 10, 2008
Dec 10, 2008
486
continue; // pick up from newline, go again.
487
488
489
490
491
} // if
break;
} // while
Feb 3, 2009
Feb 3, 2009
492
493
494
495
496
if ((ctx->eof) && (!eosok))
{
fail(ctx, "Unexpected EOF");
return 0;
} // if
Dec 13, 2008
Dec 13, 2008
497
Feb 3, 2009
Feb 3, 2009
498
return 1;
Dec 13, 2008
Dec 13, 2008
499
500
501
502
503
504
505
506
507
508
} // 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);
509
#if DEBUG_TOKENIZER
Feb 3, 2009
Feb 3, 2009
510
printf("NEXTTOKEN: %d '%s'\n", rc,
Dec 13, 2008
Dec 13, 2008
511
(ctx->tctx.token[0] == '\n') ? "\\n" : ctx->tctx.token);
512
513
514
515
516
517
#endif
return rc;
} // nexttoken
Feb 3, 2009
Feb 3, 2009
518
519
520
521
522
523
524
525
526
527
528
529
530
531
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
533
TokenizerContext *tctx = &ctx->tctx;
534
const int rc = nexttoken(ctx, 0, 1, 1, 1);
Feb 3, 2009
Feb 3, 2009
535
536
537
538
539
540
541
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
542
543
544
} // require_endline
Dec 8, 2008
Dec 8, 2008
545
static int require_comma(Context *ctx)
Dec 13, 2008
Dec 13, 2008
547
TokenizerContext *tctx = &ctx->tctx;
Dec 8, 2008
Dec 8, 2008
548
const int rc = nexttoken(ctx, 0, 1, 0, 0);
Feb 3, 2009
Feb 3, 2009
549
550
551
552
553
554
if ((rc == 0) || (!tokeq(tctx, ",")))
{
fail(ctx, "Comma expected");
return 0;
} // if
return 1;
Dec 8, 2008
Dec 8, 2008
555
} // require_comma
556
557
558
559
static int parse_register_name(Context *ctx, RegisterType *rtype, int *rnum)
{
Dec 13, 2008
Dec 13, 2008
560
TokenizerContext *tctx = &ctx->tctx;
Feb 3, 2009
Feb 3, 2009
561
562
if (!nexttoken(ctx, 0, 1, 0, 0))
return 0;
563
564
565
566
int neednum = 1;
int regnum = 0;
RegisterType regtype = REG_TYPE_TEMP;
Dec 13, 2008
Dec 13, 2008
567
if (tokeq(tctx, "r"))
568
regtype = REG_TYPE_TEMP;
Dec 13, 2008
Dec 13, 2008
569
else if (tokeq(tctx, "v"))
570
regtype = REG_TYPE_INPUT;
Dec 13, 2008
Dec 13, 2008
571
else if (tokeq(tctx, "c"))
572
regtype = REG_TYPE_CONST;
Dec 13, 2008
Dec 13, 2008
573
else if (tokeq(tctx, "i"))
574
regtype = REG_TYPE_CONSTINT;
Dec 13, 2008
Dec 13, 2008
575
else if (tokeq(tctx, "b"))
576
regtype = REG_TYPE_CONSTBOOL;
Dec 13, 2008
Dec 13, 2008
577
else if (tokeq(tctx, "oC"))
578
regtype = REG_TYPE_COLOROUT;
Dec 13, 2008
Dec 13, 2008
579
else if (tokeq(tctx, "s"))
580
regtype = REG_TYPE_SAMPLER;
Dec 13, 2008
Dec 13, 2008
581
else if (tokeq(tctx, "oD"))
582
regtype = REG_TYPE_ATTROUT;
Dec 13, 2008
Dec 13, 2008
583
else if (tokeq(tctx, "l"))
584
regtype = REG_TYPE_LABEL;
Dec 13, 2008
Dec 13, 2008
585
else if (tokeq(tctx, "p"))
586
regtype = REG_TYPE_PREDICATE;
Dec 13, 2008
Dec 13, 2008
587
else if (tokeq(tctx, "oDepth"))
Dec 13, 2008
Dec 13, 2008
588
589
590
591
{
regtype = REG_TYPE_DEPTHOUT;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
592
else if (tokeq(tctx, "aL"))
593
594
595
596
{
regtype = REG_TYPE_LOOP;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
597
else if (tokeq(tctx, "o"))
598
599
{
if (!shader_is_vertex(ctx) || !shader_version_atleast(ctx, 3, 0))
Feb 3, 2009
Feb 3, 2009
600
fail(ctx, "Output register not valid in this shader type");
601
602
regtype = REG_TYPE_OUTPUT;
} // else if
Dec 13, 2008
Dec 13, 2008
603
else if (tokeq(tctx, "oT"))
Dec 12, 2008
Dec 12, 2008
605
if (shader_is_vertex(ctx) && shader_version_atleast(ctx, 3, 0))
Feb 3, 2009
Feb 3, 2009
606
fail(ctx, "Output register not valid in this shader type");
607
608
regtype = REG_TYPE_OUTPUT;
} // else if
Dec 13, 2008
Dec 13, 2008
609
else if (tokeq(tctx, "a"))
610
611
{
if (!shader_is_vertex(ctx))
Feb 3, 2009
Feb 3, 2009
612
fail(ctx, "Address register only valid in vertex shaders.");
613
614
regtype = REG_TYPE_ADDRESS;
} // else if
Dec 13, 2008
Dec 13, 2008
615
else if (tokeq(tctx, "t"))
616
617
{
if (!shader_is_pixel(ctx))
Feb 3, 2009
Feb 3, 2009
618
fail(ctx, "Address register only valid in pixel shaders.");
619
620
regtype = REG_TYPE_ADDRESS;
} // else if
Dec 13, 2008
Dec 13, 2008
621
else if (tokeq(tctx, "vPos"))
622
623
624
625
626
{
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_POSITION;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
627
else if (tokeq(tctx, "vFace"))
628
629
630
631
632
{
regtype = REG_TYPE_MISCTYPE;
regnum = (int) MISCTYPE_TYPE_FACE;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
633
else if (tokeq(tctx, "oPos"))
634
635
636
637
638
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_POSITION;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
639
else if (tokeq(tctx, "oFog"))
640
641
642
643
644
{
regtype = REG_TYPE_RASTOUT;
regnum = (int) RASTOUT_TYPE_FOG;
neednum = 0;
} // else if
Dec 13, 2008
Dec 13, 2008
645
else if (tokeq(tctx, "oPts"))
646
647
648
649
650
651
652
653
654
655
{
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
656
657
658
659
fail(ctx, "expected register type");
regtype = REG_TYPE_CONST;
regnum = 0;
neednum = 0;
660
661
} // else
Dec 10, 2008
Dec 10, 2008
662
663
if (neednum)
{
Dec 13, 2008
Dec 13, 2008
664
665
666
667
668
// 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
669
670
if (!nexttoken_ctx(ctx, &tmptctx, 0, 1, 1, 1))
return 0;
Dec 14, 2008
Dec 14, 2008
671
else if (tokeq(&tmptctx, "["))
Dec 10, 2008
Dec 10, 2008
672
673
674
neednum = 0;
} // if
675
676
if (neednum)
{
Feb 3, 2009
Feb 3, 2009
677
678
if (!nexttoken(ctx, 0, 0, 0, 0))
return 0;
Dec 10, 2008
Dec 10, 2008
680
uint32 ui32 = 0;
Dec 13, 2008
Dec 13, 2008
681
if (!ui32fromstr(tctx->token, &ui32))
Feb 3, 2009
Feb 3, 2009
682
fail(ctx, "Invalid register index");
Dec 10, 2008
Dec 10, 2008
683
regnum = (int) ui32;
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
} // 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
711
fail(ctx, "Invalid const register index");
712
713
714
715
716
717
} // else
} // if
*rtype = regtype;
*rnum = regnum;
Feb 3, 2009
Feb 3, 2009
718
return 1;
719
720
721
} // parse_register_name
Feb 3, 2009
Feb 3, 2009
722
static void set_result_shift(Context *ctx, DestArgInfo *info, const int val)
Dec 8, 2008
Dec 8, 2008
724
if (info->result_shift != 0)
Feb 3, 2009
Feb 3, 2009
725
fail(ctx, "Multiple result shift modifiers");
Dec 8, 2008
Dec 8, 2008
726
727
info->result_shift = val;
} // set_result_shift
Dec 8, 2008
Dec 8, 2008
729
Dec 13, 2008
Dec 13, 2008
730
static int parse_destination_token(Context *ctx)
Dec 8, 2008
Dec 8, 2008
731
{
Dec 13, 2008
Dec 13, 2008
732
733
734
TokenizerContext *tctx = &ctx->tctx;
DestArgInfo *info = &ctx->dest_arg;
Dec 12, 2008
Dec 12, 2008
735
memset(info, '\0', sizeof (DestArgInfo));
736
737
738
739
// See if there are destination modifiers on the instruction itself...
while (1)
{
Feb 3, 2009
Feb 3, 2009
740
741
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
742
else if (tokeq(tctx, " "))
743
break; // done with modifiers.
Dec 13, 2008
Dec 13, 2008
744
else if (!tokeq(tctx, "_"))
Feb 3, 2009
Feb 3, 2009
745
746
747
fail(ctx, "Expected modifier or whitespace");
else if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 12, 2008
Dec 12, 2008
748
// !!! FIXME: this can be cleaned up when tokenizer is fixed.
Dec 13, 2008
Dec 13, 2008
749
else if (tokeq(tctx, "x"))
Dec 12, 2008
Dec 12, 2008
750
{
Feb 3, 2009
Feb 3, 2009
751
752
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
753
else if (tokeq(tctx, "2"))
Dec 12, 2008
Dec 12, 2008
754
set_result_shift(ctx, info, 0x1);
Dec 13, 2008
Dec 13, 2008
755
else if (tokeq(tctx, "4"))
Dec 12, 2008
Dec 12, 2008
756
set_result_shift(ctx, info, 0x2);
Dec 13, 2008
Dec 13, 2008
757
else if (tokeq(tctx, "8"))
Dec 12, 2008
Dec 12, 2008
758
759
set_result_shift(ctx, info, 0x3);
else
Feb 3, 2009
Feb 3, 2009
760
fail(ctx, "Expected modifier");
Dec 12, 2008
Dec 12, 2008
761
762
} // else if
// !!! FIXME: this can be cleaned up when tokenizer is fixed.
Dec 13, 2008
Dec 13, 2008
763
else if (tokeq(tctx, "d"))
Dec 12, 2008
Dec 12, 2008
764
{
Feb 3, 2009
Feb 3, 2009
765
766
if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
767
else if (tokeq(tctx, "8"))
Dec 12, 2008
Dec 12, 2008
768
set_result_shift(ctx, info, 0xD);
Dec 13, 2008
Dec 13, 2008
769
else if (tokeq(tctx, "4"))
Dec 12, 2008
Dec 12, 2008
770
set_result_shift(ctx, info, 0xE);
Dec 13, 2008
Dec 13, 2008
771
else if (tokeq(tctx, "2"))
Dec 12, 2008
Dec 12, 2008
772
773
set_result_shift(ctx, info, 0xF);
else
Feb 3, 2009
Feb 3, 2009
774
fail(ctx, "Expected modifier");
Dec 12, 2008
Dec 12, 2008
775
} // else if
Dec 13, 2008
Dec 13, 2008
776
else if (tokeq(tctx, "sat"))
777
info->result_mod |= MOD_SATURATE;
Dec 13, 2008
Dec 13, 2008
778
else if (tokeq(tctx, "pp"))
779
info->result_mod |= MOD_PP;
Dec 13, 2008
Dec 13, 2008
780
else if (tokeq(tctx, "centroid"))
781
782
info->result_mod |= MOD_CENTROID;
else
Feb 3, 2009
Feb 3, 2009
783
fail(ctx, "Expected modifier");
784
785
} // while
Feb 3, 2009
Feb 3, 2009
786
787
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
788
789
// !!! FIXME: predicates.
Dec 13, 2008
Dec 13, 2008
790
if (tokeq(tctx, "("))
Feb 3, 2009
Feb 3, 2009
791
792
fail(ctx, "Predicates unsupported at this time"); // !!! FIXME: ...
793
794
pushback(ctx); // parse_register_name calls nexttoken().
Feb 3, 2009
Feb 3, 2009
795
parse_register_name(ctx, &info->regtype, &info->regnum);
Feb 3, 2009
Feb 3, 2009
797
798
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
799
800
801
// !!! FIXME: can dest registers do relative addressing?
Feb 3, 2009
Feb 3, 2009
802
int invalid_writemask = 0;
Dec 14, 2008
Dec 14, 2008
803
int implicit_writemask = 0;
Dec 13, 2008
Dec 13, 2008
804
if (!tokeq(tctx, "."))
Dec 14, 2008
Dec 14, 2008
806
implicit_writemask = 1;
807
808
809
810
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
811
812
813
// !!! 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
814
815
816
fail(ctx, "Writemask specified for scalar register");
else if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
817
else if (tokeq(tctx, ""))
Feb 3, 2009
Feb 3, 2009
818
invalid_writemask = 1;
819
820
else
{
Dec 13, 2008
Dec 13, 2008
821
char *ptr = tctx->token;
822
info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 0;
Dec 8, 2008
Dec 8, 2008
823
824
825
826
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
827
if ((ptr == tctx->token) && (shader_is_pixel(ctx)))
Dec 8, 2008
Dec 8, 2008
829
830
831
832
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++; }
833
834
835
} // if
if (*ptr != '\0')
Feb 3, 2009
Feb 3, 2009
836
invalid_writemask = 1;
837
838
839
840
841
842
843
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
844
845
846
if (invalid_writemask)
fail(ctx, "Invalid writemask");
Dec 14, 2008
Dec 14, 2008
847
848
849
850
851
// !!! 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
852
fail(ctx, "Writemask specified for scalar register");
Dec 14, 2008
Dec 14, 2008
853
854
} // if
855
856
857
info->orig_writemask = info->writemask;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
Feb 3, 2009
Feb 3, 2009
858
859
860
861
{
fail(ctx, "Too many tokens");
return 1;
} // if
862
863
ctx->tokenbuf[ctx->tokenbufpos++] =
Dec 8, 2008
Dec 8, 2008
864
( ((((uint32) 1)) << 31) |
865
866
867
868
((((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
869
((((uint32) info->writemask) & 0xF) << 16) |
870
871
872
873
874
875
876
((((uint32) info->regtype) & 0x7) << 28) |
((((uint32) info->regtype) & 0x18) << 8) );
return 1;
} // parse_destination_token
Dec 10, 2008
Dec 10, 2008
877
878
879
static void set_source_mod(Context *ctx, const int negate,
const SourceMod norm, const SourceMod negated,
SourceMod *srcmod)
Dec 8, 2008
Dec 8, 2008
881
882
883
884
885
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
888
static int parse_source_token_maybe_relative(Context *ctx, const int relok)
Dec 13, 2008
Dec 13, 2008
890
TokenizerContext *tctx = &ctx->tctx;
Dec 8, 2008
Dec 8, 2008
891
892
893
int retval = 1;
if (ctx->tokenbufpos >= STATICARRAYLEN(ctx->tokenbuf))
Feb 3, 2009
Feb 3, 2009
894
895
896
897
{
fail(ctx, "Too many tokens");
return 0;
} // if
Dec 8, 2008
Dec 8, 2008
898
899
900
// mark this now, so optional relative addressing token is placed second.
uint32 *token = &ctx->tokenbuf[ctx->tokenbufpos++];
Feb 3, 2009
Feb 3, 2009
901
*token = 0;
Dec 8, 2008
Dec 8, 2008
902
903
904
SourceMod srcmod = SRCMOD_NONE;
int negate = 0;
Feb 3, 2009
Feb 3, 2009
905
906
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
907
else if (tokeq(tctx, "1"))
Dec 8, 2008
Dec 8, 2008
908
{
Feb 3, 2009
Feb 3, 2009
909
910
if (!nexttoken(ctx, 0, 1, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
911
else if (!tokeq(tctx, "-"))
Feb 3, 2009
Feb 3, 2009
912
fail(ctx, "Unexpected value");
Dec 8, 2008
Dec 8, 2008
913
914
915
else
srcmod = SRCMOD_COMPLEMENT;
} // else
Dec 13, 2008
Dec 13, 2008
916
else if (tokeq(tctx, "!"))
Dec 8, 2008
Dec 8, 2008
917
srcmod = SRCMOD_NOT;
Dec 13, 2008
Dec 13, 2008
918
else if (tokeq(tctx, "-"))
Dec 8, 2008
Dec 8, 2008
919
920
921
negate = 1;
else
pushback(ctx);
Dec 8, 2008
Dec 8, 2008
923
924
RegisterType regtype;
int regnum;
Feb 3, 2009
Feb 3, 2009
925
926
927
parse_register_name(ctx, &regtype, &regnum);
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
Dec 13, 2008
Dec 13, 2008
928
else if (!tokeq(tctx, "_"))
Dec 8, 2008
Dec 8, 2008
929
pushback(ctx);
Feb 3, 2009
Feb 3, 2009
930
931
else if (!nexttoken(ctx, 0, 0, 0, 0))
return 1;
Dec 13, 2008
Dec 13, 2008
932
else if (tokeq(tctx, "bias"))
Dec 10, 2008
Dec 10, 2008
933
set_source_mod(ctx, negate, SRCMOD_BIAS, SRCMOD_BIASNEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
934
else if (tokeq(tctx, "bx2"))
Dec 10, 2008
Dec 10, 2008
935
set_source_mod(ctx, negate, SRCMOD_SIGN, SRCMOD_SIGNNEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
936
else if (tokeq(tctx, "x2"))
Dec 10, 2008
Dec 10, 2008
937
set_source_mod(ctx, negate, SRCMOD_X2, SRCMOD_X2NEGATE, &srcmod);
Dec 13, 2008
Dec 13, 2008
938
else if (tokeq(tctx, "dz"))
Dec 10, 2008
Dec 10, 2008
939
set_source_mod(ctx, negate, SRCMOD_DZ, SRCMOD_NONE, &srcmod);
Dec 13, 2008
Dec 13, 2008
940
else if (tokeq(tctx, "dw"))
Dec 10, 2008
Dec 10, 2008
941
set_source_mod(ctx, negate, SRCMOD_DW, SRCMOD_NONE, &srcmod);
Dec 13, 2008
Dec 13, 2008
942
else if (tokeq(tctx, "abs"))
Dec 10, 2008
Dec 10, 2008
943
set_source_mod(ctx, negate, SRCMOD_ABS, SRCMOD_ABSNEGATE, &srcmod);
Dec 8, 2008
Dec 8, 2008
944
else
Feb 3, 2009
Feb 3, 2009
945
fail(ctx, "Invalid source modifier");
Feb 3, 2009
Feb 3, 2009
947
948
if (!nexttoken(ctx, 0, 1, 1, 1))
return 1;
Dec 8, 2008
Dec 8, 2008
950
uint32 relative = 0;
Dec 13, 2008
Dec 13, 2008
951
if (!tokeq(tctx, "["))
Dec 8, 2008
Dec 8, 2008
952
953
954
pushback(ctx); // not relative addressing?
else
{
Feb 3, 2009
Feb 3, 2009
955
956
957
958
959
960
if (!relok)
fail(ctx, "Relative addressing not permitted here.");
else
retval++;
parse_source_token_maybe_relative(ctx, 0);
Dec 8, 2008
Dec 8, 2008
961
relative = 1;
Feb 3, 2009
Feb 3, 2009
962
963
if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
964
else if (!tokeq(tctx, "+"))
Dec 10, 2008
Dec 10, 2008
965
pushback(ctx);
Feb 3, 2009
Feb 3, 2009
966
967
else if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 10, 2008
Dec 10, 2008
968
969
970
971
972
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
973
if (!ui32fromstr(tctx->token, &ui32))
Feb 3, 2009
Feb 3, 2009
974
fail(ctx, "Invalid relative addressing offset");
Dec 10, 2008
Dec 10, 2008
975
976
977
regnum += (int) ui32;
} // else
Feb 3, 2009
Feb 3, 2009
978
979
if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
980
else if (!tokeq(tctx, "]"))
Feb 3, 2009
Feb 3, 2009
981
fail(ctx, "Expected ']'");
Dec 8, 2008
Dec 8, 2008
982
} // else
Feb 3, 2009
Feb 3, 2009
984
985
if (!nexttoken(ctx, 0, 1, 1, 1))
return retval;
Dec 8, 2008
Dec 8, 2008
986
Feb 3, 2009
Feb 3, 2009
987
int invalid_swizzle = 0;
Dec 8, 2008
Dec 8, 2008
988
uint32 swizzle = 0;
Dec 13, 2008
Dec 13, 2008
989
if (!tokeq(tctx, "."))
Dec 8, 2008
Dec 8, 2008
990
991
992
993
{
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
994
else if (scalar_register(ctx->shader_type, regtype, regnum))
Feb 3, 2009
Feb 3, 2009
995
996
997
fail(ctx, "Swizzle specified for scalar register");
else if (!nexttoken(ctx, 0, 1, 0, 0))
return retval;
Dec 13, 2008
Dec 13, 2008
998
else if (tokeq(tctx, ""))
Feb 3, 2009
Feb 3, 2009
999
invalid_swizzle = 1;
Dec 8, 2008
Dec 8, 2008
1000
else