Skip to content

Latest commit

 

History

History
2073 lines (1758 loc) · 58.1 KB

mojoshader_assembler.c

File metadata and controls

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