Skip to content

Latest commit

 

History

History
1914 lines (1593 loc) · 55.9 KB

mojoshader_assembler.c

File metadata and controls

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